package cn.mw.cmdb.service.impl;

import cn.hutool.core.bean.PropDesc;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.json.JSONUtil;
import cn.mw.cmdb.api.MwCmdbBussinessType;
import cn.mw.cmdb.entity.*;
import cn.mw.cmdb.enums.*;
import cn.mw.cmdb.exception.*;
import cn.mw.cmdb.listener.InstanceChangeEventLister;
import cn.mw.cmdb.listener.InstanceListenersManager;
import cn.mw.cmdb.mongoMapper.AssetsCodeCacheMapper;
import cn.mw.cmdb.mongoMapper.AssetsInterfaceMapper;
import cn.mw.cmdb.mongoMapper.InstanceInfoMapper;
import cn.mw.cmdb.param.*;
import cn.mw.cmdb.param.zabbixResult.MwZabbixItemResultParam;
import cn.mw.cmdb.processor.BusinessProcessEventLogger;
import cn.mw.cmdb.processor.BusinessProcessNetwork;
import cn.mw.cmdb.processor.MonitorParamContext;
import cn.mw.cmdb.processor.MonitorProcessor;
import cn.mw.cmdb.service.AssetsManageService;
import cn.mw.cmdb.service.ModelService;
import cn.mw.cmdb.service.MwMonitorProcessorConvert;
import cn.mw.cmdb.trigger.MwCmdbTrigger;
import cn.mw.cmdb.trigger.MwCmdbTriggerManager;
import cn.mw.cmdb.trigger.RecordTrigger;
import cn.mw.cmdb.trigger.TriggerContext;
import cn.mw.cmdb.util.CMDBCommonUtil;
import cn.mw.cmdb.util.CMDBTool;
import cn.mw.cmdb.util.JsonComparatorUtil;
import cn.mw.cmdb.view.ViewConvertContext;
import cn.mw.cmdb.view.ViewManager;
import cn.mw.components.mongodb.entity.CriteriaOpsType;
import cn.mw.components.mongodb.entity.GroupCalculateMethodEnum;
import cn.mw.components.mongodb.entity.GroupSearchOperation;
import cn.mw.components.mongodb.entity.SubCondition;
import cn.mw.components.mongodb.exception.BusinessException;
import cn.mw.components.mongodb.tool.CriteriaWrapper;
import cn.mw.components.mongodb.tool.MongoUtils;
import cn.mw.log.enums.BusinessLogType;
import cn.mw.log.enums.LogLevel;
import cn.mw.main.api.common.ZabbixDubboService;
import cn.mw.microMonitorCommon.api.alert.AlertApiService;
import cn.mw.microMonitorCommon.api.cmdb.TableIdEnum;
import cn.mw.microMonitorCommon.api.common.MwEngineManageService;
import cn.mw.microMonitorCommon.api.common.ServiceException;
import cn.mw.microMonitorCommon.api.user.MwUserApi;
import cn.mw.microMonitorCommon.baseModel.BaseModelInfo;
import cn.mw.microMonitorCommon.constant.Constants;
import cn.mw.microMonitorCommon.constant.DateConstant;
import cn.mw.microMonitorCommon.constants.ZabbixItemConstant;
import cn.mw.microMonitorCommon.entity.alertDto.CurrentAlertDto;
import cn.mw.microMonitorCommon.entity.cmdb.ModelExportDataInfoListParam;
import cn.mw.microMonitorCommon.entity.cmdb.ModelExportDataInfoParam;
import cn.mw.microMonitorCommon.entity.cmdb.MwWebMonitorDto;
import cn.mw.microMonitorCommon.entity.common.MwTPServerTable;
import cn.mw.microMonitorCommon.entity.logmanger.InstanceChangeHisVO;
import cn.mw.microMonitorCommon.entity.userDTO.GroupDTO;
import cn.mw.microMonitorCommon.entity.userDTO.OrgDTO;
import cn.mw.microMonitorCommon.entity.zabbix.MWZabbixAPIResult;
import cn.mw.microMonitorCommon.entity.zabbix.MWZabbixWebMonitorVo;
import cn.mw.microMonitorCommon.entity.zabbix.MWZabbixWebStepVo;
import cn.mw.microMonitorCommon.entity.zabbix.MwModelWebMonitorTriggerParam;
import cn.mw.microMonitorCommon.enums.TriggerAlarmLevelEnum;
import cn.mw.microMonitorCommon.operatorlog.client.MwLogClientSimple;
import cn.mw.microMonitorCommon.param.AssetsOperatorHisSearchParam;
import cn.mw.microMonitorCommon.security.dto.MwUser;
import cn.mw.microMonitorCommon.security.utils.SecurityUtils;
import cn.mw.microMonitorCommon.util.*;
import cn.mw.microMonitorCommon.utils.DatabaseUtils;
import cn.mw.scanengine.service.ScanEngineService;
import cn.mw.scanengine.view.DeviceInfoView;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.SerializationUtils;
import org.apache.commons.lang3.StringUtils;
import org.bson.Document;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.BulkOperations;
import org.springframework.data.mongodb.core.aggregation.Aggregation;
import org.springframework.data.mongodb.core.aggregation.AggregationResults;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.util.Pair;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.time.DayOfWeek;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;

import static cn.mw.cmdb.entity.InputDataAuth.*;
import static cn.mw.cmdb.entity.InstanceInfo.SearchPrefix;
import static cn.mw.cmdb.entity.ModelInfo.prefix;
import static cn.mw.cmdb.entity.PropertyType.relationIdKey;
import static cn.mw.cmdb.entity.PropertyType.relationPath;
import static cn.mw.cmdb.enums.ModelConfigKeyEnum.relationParentModel;
import static cn.mw.cmdb.enums.MonitorMethodEnum.*;
import static cn.mw.cmdb.enums.PageDescEnum.Modelinstance;
import static cn.mw.cmdb.enums.QueryRoomCabinetType.QueryCabinetByRoom;
import static cn.mw.cmdb.enums.QueryRoomCabinetType.QueryInstanceByCabinet;
import static cn.mw.cmdb.enums.ZabbixAssetsStatusEnum.*;
import static cn.mw.cmdb.param.FunctionModuleEnum.enableMonitor;
import static cn.mw.cmdb.processor.MonitorValue.*;
import static cn.mw.cmdb.service.impl.InstanceViewImpl.*;
import static cn.mw.cmdb.util.AssetCodeGenerator.*;
import static cn.mw.cmdb.util.BaseUtil.getNowLocalTime;
import static cn.mw.cmdb.util.CMDBCommonUtil.sortListByField;
import static cn.mw.cmdb.util.CMDBTool.genMongoUpdateByMap;
import static cn.mw.cmdb.util.CMDBTool.getFieldInfoToMap;
import static cn.mw.cmdb.util.ValConvertUtil.*;
import static cn.mw.cmdb.view.InstanceListViewConverter.checkView;
import static cn.mw.cmdb.view.InstanceListViewConverter.serviceManage;
import static cn.mw.cmdb.view.ViewConvert.ascSortModel;
import static cn.mw.cmdb.viewProcessor.ModelViewCabinetProcess.*;
import static cn.mw.cmdb.viewProcessor.ModelViewRoomProcess.layoutDataRoom;
import static cn.mw.cmdb.viewProcessor.ModelViewUNumProcess.*;
import static cn.mw.components.mongodb.entity.MongoPropertyType.strValueConvert;
import static cn.mw.microMonitorCommon.util.ListMapObjUtils.beanToMap;

/*
 * 模型实例管理
 */
@Slf4j
public class InstanceServiceImpl extends ModelBaseServiceImpl<InstanceInfo, Object> {

    private static final int BATCH_SIZE = 20;

    public static final String UniqueAlertSep = ":";
    public static final String FacilityDescriptoSuffix = "-0000000";
    public static final String relationRoomPath = SearchPrefix + "." + relationRoom;
    public static final String relationRoomIdPath = SearchPrefix + "." + relationRoom + "." + relationIdKey;
    public static final String relationCabinetPath = SearchPrefix + "." + relationCabinet + "." + relationIdKey;
    public static final String relationCabinetIdPath = SearchPrefix + "." + relationCabinet + "." + relationIdKey;
    public static final String deviceUIndexPath = SearchPrefix + "." + deviceUIndex;
    public static final String cabinetPositionPath = SearchPrefix + "." + cabinetPosition;
    public static final String cabinetUNumPath = SearchPrefix + "." + UNum;


    public static final String tagUManageIdKey = "tagUManageId";
    public static final String UManageTipMessageKey = "UManageTipMessage";
    public static final String UManageTipMessagePath = SearchPrefix + "." + UManageTipMessageKey;
    public static final String tagUManageIdPath = SearchPrefix + "." + tagUManageIdKey;
    public static final List<String> removeFieldDataList = Arrays.asList(OrgKey, OrgIdsKey, GroupKey, UserKey, OrgNameKey, GroupNameKey, UserNameKey);

    public static final String ID = "instanceService";

    public static final String KEY_ID = "_id";

    public static final String KEY_IDS = "ids";
    public static final String PAGE_ID = "pageId";
    public static final String PROCESS_ID = "processId";

    public static List<String> ignoreList = Arrays.asList(KEY_IDS, PAGE_ID, PROCESS_ID);
    //导入修改不可以变更的字段属性(创建人，创建时间，修改人，修改时间，模型分组，模型名称)
    public static final List<String> dataAuthInfoList = Arrays.asList(CMDBTool.getFieldName(InstanceInfo::getCreater), CMDBTool.getFieldName(InstanceInfo::getModifier),
            CMDBTool.getFieldName(InstanceInfo::getCreateTime), CMDBTool.getFieldName(InstanceInfo::getModificationTime), mwModelGroupNameKey, mwModelNameKey);

    public static List<String> alertLevelList = Arrays.asList("告警", "严重", "紧急");


    private static final String WEB_TEST_TIME = "web.test.time";

    private static final String WEB_TEST_RSPCODE = "web.test.rspcode";

    private static final String WEB_TEST_ERROR = "web.test.error";

    public static final String COUNT = "count";

    public static final String SUMMARY_EMPTY = "——";

    private Set<String> resetPrefixFields;

    public static final String mapperKey = "instanceInfoMapper";
    public static final String beforeInstanceKey = "beforeInstance";

    public static final ObjectMapper mapper = new ObjectMapper();

    private InstanceInfoMapper instanceInfoMapper;


    private AssetsInterfaceMapper assetsInterfaceMapper;

    private AlertApiService alertApiService;

    private CmdbServiceManage cmdbServiceManage;

    private ModuleIDManager moduleIDManager;

    private List<InstanceChangeEventLister> listerList;

    private ScanEngineService scanEngineService;
    private AssetsCodeCacheMapper assetsCodeCacheMapper;

    private MwUserApi userApi;

    private ZabbixDubboService zabbixDubboService;

    private MwEngineManageService mwEngineManageService;

    private static ThreadLocal<List<AddAndUpdInstanceContext>> addAndUpdInstanceContextThreadLocal = new ThreadLocal<>();

    public void removeAddAndUpdInstanceContextThreadLocal() {
        addAndUpdInstanceContextThreadLocal.remove();
    }


    private static ConcurrentHashMap<String, List<String>> assetsCodeCacheThreadMap = new ConcurrentHashMap();

    private static CopyOnWriteArrayList<AssetsCodeCacheDTO> assetsCodeCacheThreadAllList = new CopyOnWriteArrayList();

    private static final Lock lock = new ReentrantLock();
    private MwLogClientSimple logClientSimple;

    public final List<String> specialHandleList = Arrays.asList(MW_ASSET_TYPE_Key);

    public InstanceServiceImpl(InstanceInfoMapper instanceInfoMapper, CmdbServiceManage cmdbServiceManage
            , ModuleIDManager moduleIDManager, ZabbixDubboService zabbixDubboService
            , List<InstanceChangeEventLister> listerList, ScanEngineService scanEngineService, AlertApiService alertApiService
            , MwUserApi userApi, AssetsCodeCacheMapper assetsCodeCacheMapper, AssetsInterfaceMapper assetsInterfaceMapper
            , MwEngineManageService mwEngineManageService) {
        this.instanceInfoMapper = instanceInfoMapper;
        this.cmdbServiceManage = cmdbServiceManage;
        this.moduleIDManager = moduleIDManager;
        this.zabbixDubboService = zabbixDubboService;
        this.scanEngineService = scanEngineService;
        this.listerList = listerList;
        this.alertApiService = alertApiService;
        this.userApi = userApi;
        this.assetsCodeCacheMapper = assetsCodeCacheMapper;
        this.assetsInterfaceMapper = assetsInterfaceMapper;
        this.mwEngineManageService = mwEngineManageService;
        init();
    }

    public InstanceServiceImpl() {
        this.logClientSimple = SpringUtil.getBean(MwLogClientSimple.class);
    }

    @Override
    public InstanceInfo genObject() {
        return new InstanceInfo();
    }

    /*
     * 添加实例,并处理是否纳管
     */
    @Override
    public Object doAdd(InstanceInfo param) throws Exception {
        if (Strings.isNullOrEmpty(param.getModelId())) {
            throw new NotFindModelException("");
        }
        InstanceInfoAddConsumer instanceInfoAddConsumer = new InstanceInfoAddConsumer();
        batchAddAndUpdInstance(Arrays.asList(param), true, instanceInfoAddConsumer);
        return instanceInfoAddConsumer.getRet();
    }

    @Override
    public boolean doUpdate(InstanceInfo param) throws Exception {
        InstanceInfo beforeInstance = getInstanceInfoById(param.getId());

        Map<String, Object> map = new HashMap<>();
        map.put(mapperKey, instanceInfoMapper);
        map.put(beforeInstanceKey, beforeInstance);
        try {
            //实例变更通知处理
            Object obj = notifyUpdateChangeFunction(map, Arrays.asList(param));
            if (obj != null && obj instanceof List) {
                List list = (List) obj;
                for (Object info : list) {
                    if (info instanceof MwUpdateInstanceCheckInfoParam) {
                        MwUpdateInstanceCheckInfoParam infoParam = (MwUpdateInstanceCheckInfoParam) info;
                        String message = infoParam.getMessage();
                        if (!Strings.isNullOrEmpty(message)) {
                            throw new WarnTitleException(message);
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("notifyUpdateChangeFunction fail to::", e);
        }
        InstanceInfoUpdConsumer instanceInfoUpdConsumer = new InstanceInfoUpdConsumer();
        batchAddAndUpdInstance(Arrays.asList(param), false, instanceInfoUpdConsumer);
        boolean ret = instanceInfoUpdConsumer.isRet();
//        //修改成功，判断是否修改轮询引擎
//        if (ret) {
//            //判断轮询引擎是否修改
//            if (beforeInstance != null && param.getPollingEngine() != null && !param.getPollingEngine().equals(beforeInstance.getPollingEngine())) {
//                batchUpdateMonitorProxy(Arrays.asList(param), param.getProxyType(), param.getPollingEngine());
//            }
//        }


        return instanceInfoUpdConsumer.isRet();
    }


    /**
     * 流程修改实例 批量修改
     *
     * @param param
     * @return
     * @throws Exception
     */
    public boolean customUpdate(Map param) throws Exception {
        List<String> idList = new ArrayList<>();
        //流程修改实例，批量修改，ids是必输入值,是list格式
        if (param != null && param.get(KEY_IDS) != null) {
            idList = CMDBTool.stringToList(param.get(KEY_IDS).toString());
        }
        if (CollectionUtils.isNotEmpty(idList)) {
            Query query = new Query(CriteriaWrapper.where(InstanceInfo::getId).in(idList));
            ModelService modelService = cmdbServiceManage.getModelService(ID);
            Object convert = cmdbServiceManage.convert(modelService, (Map) param);
            //将map参数转为InstanceInfo
            if (convert != null && convert instanceof InstanceInfo) {
                InstanceInfo instanceInfo = (InstanceInfo) convert;
                Map<String, PropertyInfo> propertyInfoById = new HashMap<>();
                String modelId = instanceInfo.getModelId();
                if (!Strings.isNullOrEmpty(modelId)) {
                    ModelInfo modelInfo = getModelInfo(modelId);
                    propertyInfoById = modelInfo.getPropertyInfoById();
                }
                Map<String, Object> map = new HashMap<>();
                map.put(mapperKey, instanceInfoMapper);
                try {
                    //实例变更通知处理
                    Object obj = notifyUpdateChangeFunction(map, Arrays.asList(param));
                } catch (Exception e) {
                    log.error("notifyUpdateChangeFunction fail to::", e);
                }
                //根据map字段产生更新信息
                Update update = CMDBTool.genMongoUpdate(instanceInfo.getData(), InstanceInfo.SearchPrefix, ignoreList, propertyInfoById);
                //根据类注解信息产生更新信息
                update = CMDBTool.genMongoUpdate(instanceInfo, null, update);
                instanceInfoMapper.updateMulti(query, update);
                return true;
            }
        }
        return false;
    }

    @Override
    boolean doRemove(InstanceInfo param) throws Exception {
        //删除资产监控
        InstanceInfo delInstanceInfo = instanceInfoMapper.findById(param.getId());
        AssetsManageService assetsManageService = SpringUtils.getBean(AssetsManageServiceImpl.class);
        assetsManageService.delMonitor(delInstanceInfo);

        //删除通知
        Map<String, Object> map = new HashMap<>();
        map.put(mapperKey, instanceInfoMapper);
        try {
            //实例删除通知处理
            notifyDeleteChangeFunction(map, Arrays.asList(param));
        } catch (Exception e) {
            log.error("notifyDeleteChangeFunction fail to::", e);
        }

        CMDBTool.remove(instanceInfoMapper, param.getId(), InstanceInfo.class, true);
        return true;
    }

    @Override
    public Object doBatchAdd(Object params) throws Exception {
        InstanceInfoAddConsumer instanceInfoAddConsumer = new InstanceInfoAddConsumer();
        if (params instanceof List) {
            List<InstanceInfo> paramList = (List<InstanceInfo>) params;
            batchAddAndUpdInstance(paramList, true, instanceInfoAddConsumer);
//            //新增通知
//            Map<String, Object> map = new HashMap<>();
//            map.put(mapperKey, instanceInfoMapper);
//            //实例变更通知处理
//            notifyAddChangeFunction(map, paramList);
        }
        Object ret = instanceInfoAddConsumer.getRet();
        return ret;
    }


    /**
     * 资产视图实例批量更新
     *
     * @return
     */
    @Override
    public boolean doBatchUpdate(Object param) throws Exception {
        BatchEditorViewInstance params = (BatchEditorViewInstance) param;
        if (params.getOrgs() == null) {
            params.setOrgIds(null);
        }
        Map m = ListMapObjUtils.beanToMap(params);
        Query query = new Query(CriteriaWrapper.where(InstanceInfo::getId).in(params.getInstanceIds()));
        //根据map字段产生更新信息
        Update update = CMDBTool.genMongoInstanceUpdate(params, InstanceInfo.SearchPrefix);

        //定时任务执行时，修改时间不更新
        if (params != null && !booleanValueConvert(params.getTimeTaskFlag())) {
            //逻辑删除时，设置修改时间，修改人
            if (SecurityUtils.getUser() != null) {
                Long modifier = SecurityUtils.getUserId();
                update.set(CMDBTool.getFieldName(InstanceInfo::getModifier), modifier);
                update.set(CMDBTool.getFieldName(InstanceInfo::getModificationTime), getNowLocalTime());
            }
        }
        instanceInfoMapper.updateMulti(query, update);

        //批量修改同步数据处理
        batchEditorSyncHandle(params);

        //非定时任务执行时，保存变更历史记录
        if (params != null && !booleanValueConvert(params.getTimeTaskFlag())) {
            // 批量更新数据的变更历史记录
            InstanceSearchParam instanceSearchParam = new InstanceSearchParam();
            instanceSearchParam.setInstanceIds(params.getInstanceIds());
            List<InstanceInfo> instanceInfos = doSelectList(instanceSearchParam);
            BusinessProcessEventLogger bean = SpringUtils.getBean(BusinessProcessEventLogger.class);
            bean.addBatchUpdInstanceInfo(instanceInfos);
        }
        return true;
    }

    /**
     * 批量更新(多条数据不同字段批量修改)
     *
     * @return
     */
    public Object doBatchUpdateMulti(Object params) throws Exception {
        InstanceInfoAddConsumer instanceInfoAddConsumer = new InstanceInfoAddConsumer();
        ModelService modelService = cmdbServiceManage.getModelService(ID);
        List<InstanceInfo> list = new ArrayList<>();
        if (params != null && params instanceof List) {
            List mapList = (List) params;
            for (Object obj : mapList) {
                if (obj != null && obj instanceof Map) {
                    Map map = (Map) obj;
                    Object convert = cmdbServiceManage.convert(modelService, map);
                    if (convert != null && convert instanceof InstanceInfo) {
                        InstanceInfo instanceInfo = (InstanceInfo) convert;
                        list.add(instanceInfo);
                    }
                }
                if (obj != null && obj instanceof InstanceInfo) {
                    InstanceInfo instanceInfo = (InstanceInfo) obj;
                    list.add(instanceInfo);
                }
            }
            Map<String, Object> map = new HashMap<>();
            map.put(mapperKey, instanceInfoMapper);
            try {
                //实例变更通知处理
                Object obj = notifyUpdateChangeFunction(map, list);
            } catch (Exception e) {
                log.error("notifyUpdateChangeFunction fail to::", e);
            }
            log.info("doBatchUpdateMulti::" + list);
            batchAddAndUpdInstance(list, false, instanceInfoAddConsumer);
        }
        return instanceInfoAddConsumer.getRet();
    }

    @Override
    public InstanceInfo doSelectById(Object id) {
        Object sid = id;
        if (id instanceof InstanceInfo) {
            sid = ((InstanceInfo) id).getId();
        }
        InstanceInfo instanceInfo = instanceInfoMapper.findById(sid);
        if (instanceInfo != null) {
            //字段解密
//            instanceInfo.decryptInfoHandle();

            // 获取当前实例状态
            try {
                String currentState = instanceInfo.getItemAssetsStatus();
                getAssetsStatusByOne(instanceInfo);
                // 实例状态与表中不一致 需要更新状态值
                if (!StringUtils.equals(currentState, instanceInfo.getItemAssetsStatus())) {
                    BatchEditorViewInstance batchEditorViewInstance = new BatchEditorViewInstance();
                    batchEditorViewInstance.setInstanceIds(Collections.singletonList(instanceInfo.getId()));
                    batchEditorViewInstance.setItemAssetsStatus(instanceInfo.getItemAssetsStatus());
                    batchUpdate(batchEditorViewInstance);
                }
            } catch (Exception e) {
                log.error("getAssetsStatus error!", e);
            }
        }
        return instanceInfo;
    }

    public InstanceInfo getInstanceInfoById(String instanceId) {
        InstanceInfo instanceInfo = instanceInfoMapper.findById(instanceId);
        if (instanceInfo != null) {
            //字段解密
            instanceInfo.decryptInfo();
        }
        return instanceInfo;
    }


    public void updateInstanceCustom(Query query, Update update) {
        instanceInfoMapper.updateFirst(query, update);
    }


    /**
     * 根据资产Id查询实例内置属性
     *
     * @param instanceId
     * @param key
     * @return
     */
    public Object queryInstanceMapInfo(String instanceId, String key) {
        Object obj = null;
        InstanceInfo instanceInfo = instanceInfoMapper.findById(instanceId);
        if (instanceInfo != null && instanceInfo.getData().containsKey(key)) {
            obj = instanceInfo.getData().get(key);
        }
        return obj;
    }

    @Override
    public List<InstanceInfo> doSelectList(Object param) throws Exception {
        InstanceSearchParam instanceSearchParam = (InstanceSearchParam) param;
        instanceSearchParam.convert();
        long time1 = System.currentTimeMillis();
        Criteria criteria = doCriteria(instanceSearchParam);
        long time2 = System.currentTimeMillis();
        List<InstanceInfo> ret = CMDBTool.selectAuthorizedList(InstanceInfo.class, instanceInfoMapper, criteria, instanceSearchParam);
        long time3 = System.currentTimeMillis();
        //默认查询
        if (!instanceSearchParam.isEnableMonitorStatus()) {
            //资产告警状态
            getInstanceAlertInfo(ret);
        }
        log.info("instance:doSelectList:doCriteria:" + (time2 - time1) + "ms;selectAuthorizedList:" + (time3 - time2) + "ms");
        return ret;
    }

    public List<InstanceInfo> doListByIdsNotAuth(List<String> ids) throws Exception {
        List<InstanceInfo> ret = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(ids)) {
            Query query = new Query(CriteriaWrapper.where(InstanceInfo::getId).in(ids));
            query.addCriteria(CriteriaWrapper.where(InstanceInfo::getDelFlag).is(false));
            ret = instanceInfoMapper.find(query);
        }
        return ret;
    }

    public List<InstanceInfo> doListByQueryNotAuth(Query query) throws Exception {
        List<InstanceInfo> ret = new ArrayList<>();
        if (null != query) {
            query.addCriteria(CriteriaWrapper.where(InstanceInfo::getDelFlag).is(false));
            ret = instanceInfoMapper.find(query);
        }
        return ret;
    }

    public List<InstanceInfo> doListByModelIdsNotAuth(List<String> modelIds) throws Exception {
        List<InstanceInfo> ret = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(modelIds)) {
            Query query = new Query(CriteriaWrapper.where(InstanceInfo::getModelId).in(modelIds));
            query.addCriteria(CriteriaWrapper.where(InstanceInfo::getDelFlag).is(false));
            ret = instanceInfoMapper.find(query);
        }
        return ret;
    }

    public void updateMultiInstance(List<Pair<Query, Update>> updateList) throws Exception {
        if (CollectionUtils.isNotEmpty(updateList)) {
            BulkOperations operations = instanceInfoMapper.bulkOps(BulkOperations.BulkMode.UNORDERED, InstanceInfo.class);
            operations.updateMulti(updateList);
            operations.execute();
        }
    }

    public List<InstanceInfo> selectListByIds(Object param) throws Exception {
        InstanceSearchParam instanceSearchParam;
        if (param instanceof InstanceSearchParam) {
            instanceSearchParam = (InstanceSearchParam) param;
        } else if (param instanceof List) {
            instanceSearchParam = new InstanceSearchParam();
            List<String> instanceIds = (List) param;
            if (CollectionUtils.isEmpty(instanceIds)) {
                return new ArrayList<>();
            }
            instanceSearchParam.setInstanceIds(instanceIds);
        } else {
            return new ArrayList<>();
        }
        instanceSearchParam.convert();
        instanceSearchParam.setIgnoreDataAuth(true);
        Criteria criteria = doCriteria(instanceSearchParam);
        long time2 = System.currentTimeMillis();
        List<InstanceInfo> ret = CMDBTool.selectAuthorizedList(InstanceInfo.class, instanceInfoMapper, criteria, instanceSearchParam);
        return ret;
    }

    @Override
    public boolean doBatchRemove(Object param) throws Exception {
        InstanceIdsParam params = (InstanceIdsParam) param;
        Query query = new Query(CriteriaWrapper.where(InstanceInfo::getId).in(params.getIds()));
        query.addCriteria(CriteriaWrapper.where(InstanceInfo::getDelFlag).is(false));
        List<InstanceInfo> ret = instanceInfoMapper.find(query);

        //删除通知
        Map<String, Object> map = new HashMap<>();
        map.put(mapperKey, instanceInfoMapper);
        try {
            //实例删除通知处理
            notifyDeleteChangeFunction(map, ret);
        } catch (InstanceExistException instanceExistException) {
            throw instanceExistException;
        } catch (DelInstanceException delInstanceException) {
            throw delInstanceException;
        } catch (ServiceException serviceException) {
            throw serviceException;
        } catch (Exception e) {
            log.error("notifyDeleteChangeFunction fail to::", e);
        }

        //批量删除监控服务器资产
        batchDelMonitorAssets(ret);

        // 删除web监测
        String webMonitorModelId = SpringUtils.getPropertiesValue("base.webMonitor.modelId");
        Map<Integer, List<InstanceInfo>> serverId2InstanceInfoMap = ret.stream().collect(Collectors.groupingBy(InstanceInfo::getMonitorServerId));
        for (Map.Entry<Integer, List<InstanceInfo>> entry : serverId2InstanceInfoMap.entrySet()) {
            List<String> webIds = new ArrayList<>();
            for (InstanceInfo item : entry.getValue()) {
                if (StringUtils.equals(item.getModelId(), webMonitorModelId)
                        && item.getData().get(DatabaseUtils.getFieldName(MwWebMonitorDto::getMw_httpTestId)) != null) {
                    webIds.add(item.getData().get(DatabaseUtils.getFieldName(MwWebMonitorDto::getMw_httpTestId)).toString());
                }
            }
            if (CollectionUtils.isNotEmpty(webIds)) {
                zabbixDubboService.getZabbixApiResult("httpTestDelete", entry.getKey(), webIds);
            }
        }

        CMDBTool.remove(instanceInfoMapper, params.getIds(), InstanceInfo.class, true);

        // 记录批量删除操作
        BusinessProcessEventLogger bean = SpringUtils.getBean(BusinessProcessEventLogger.class);
        bean.addBatchRemoveInstanceInfo(ret, "");
        return true;
    }

    public List<InstanceGroupByPathAndStatus> groupCountByPathAndStatus(InstanceSearchParam param) throws Exception {
        GroupSearchOperation groupSearchOperation = new GroupSearchOperation();
        param.convert();
        Criteria criteria = doCriteria(param);
        String pathName = CMDBTool.getFieldName(InstanceInfo::getPath);
        groupSearchOperation.addGroupField(pathName, pathName);

        String itemAssetsStatus = CMDBTool.getFieldName(InstanceInfo::getItemAssetsStatus);
        groupSearchOperation.addGroupField(itemAssetsStatus, itemAssetsStatus);

        String data = CMDBTool.getFieldName(InstanceInfo::getData);
        groupSearchOperation.addGroupField(data, data);

        String financeParentId = CMDBTool.getFieldName(InstanceInfo::getFinanceParentId);
        groupSearchOperation.addGroupField(financeParentId, financeParentId);

        String groupId = CMDBTool.getFieldName(InstanceInfo::getGroupId);
        groupSearchOperation.addGroupField(groupId, groupId);

        groupSearchOperation.addGroupField("instanceId", "_id");

        groupSearchOperation.addCalculateField(CMDBTool.getFieldName(InstanceGroupByPathAndStatus::getCount), GroupCalculateMethodEnum.count, null);
        param.setGroupSearchOperation(groupSearchOperation);

        List<InstanceGroupByPathAndStatus> ret = CMDBTool.aggregateAuthorizedList(InstanceGroupByPathAndStatus.class, instanceInfoMapper, criteria, param);
        return ret;
    }

    public List<InstanceGroupBySingleAndStatus> groupCountBySingle(String groupName, InstanceSearchParam param) throws Exception {
        Criteria criteria = doCriteria(param);
        GroupSearchOperation groupSearchOperation = new GroupSearchOperation();
        groupSearchOperation.addGroupField(CMDBTool.getFieldName(InstanceGroupBySingleAndStatus::getDataId), groupName);

        String itemAssetsStatus = CMDBTool.getFieldName(InstanceInfo::getItemAssetsStatus);
        groupSearchOperation.addGroupField(itemAssetsStatus, itemAssetsStatus);

        String data = CMDBTool.getFieldName(InstanceInfo::getData);
        groupSearchOperation.addGroupField(data, data);

        groupSearchOperation.addCalculateField(CMDBTool.getFieldName(InstanceGroupByPathAndStatus::getCount), GroupCalculateMethodEnum.count, null);
        param.setGroupSearchOperation(groupSearchOperation);
        List<InstanceGroupBySingleAndStatus> ret = CMDBTool.aggregateAuthorizedList(InstanceGroupBySingleAndStatus.class, instanceInfoMapper, criteria, param);
        return ret;
    }

    //聚合查询,返回实例的关联信息
    public List<InstanceInfoExtend> aggregateList(Object param) throws Exception {
        long time1 = System.currentTimeMillis();

        InstanceSearchParam instanceSearchParam = (InstanceSearchParam) param;
        instanceSearchParam.convert();
        Criteria criteria = doCriteria(instanceSearchParam);
        long time2 = System.currentTimeMillis();
        log.info("资产聚合查询:");
        List<InstanceInfoExtend> ret = CMDBTool.aggregateAuthorizedList(InstanceInfoExtend.class, instanceInfoMapper, criteria, instanceSearchParam);
        long time3 = System.currentTimeMillis();
        //资产告警状态
        getInstanceAlertInfo(ret);
        long time4 = System.currentTimeMillis();
        log.info("aggregateList查询,参数组合耗时:" + (time2 - time1) + "ms;聚合查询耗时:" + (time3 - time2) + "ms;告警查询耗时:" + (time4 - time3) + "ms");
        return ret;
    }

    public int aggregateCount(InstanceSearchParam instanceSearchParam) throws Exception {
        instanceSearchParam.convert();
        Criteria criteria = doCriteria(instanceSearchParam);
        return CMDBTool.aggregateAuthorizedCount(InstanceInfoExtend.class, instanceInfoMapper, criteria, instanceSearchParam);
    }

    public InstanceInfoExtend selectAggregateById(String id) throws Exception {
        InstanceSearchParam instanceSearchParam = new InstanceSearchParam();
        instanceSearchParam.setInstanceId(id);
        instanceSearchParam.convert();
        Criteria criteria = doCriteria(instanceSearchParam);
        InstanceInfoExtend instanceInfoExtend = new InstanceInfoExtend();
        List<InstanceInfoExtend> ret = CMDBTool.aggregateAuthorizedList(InstanceInfoExtend.class, instanceInfoMapper, criteria, instanceSearchParam);
        if (CollectionUtils.isNotEmpty(ret)) {
            instanceInfoExtend = ret.get(0);
        }
        return instanceInfoExtend;
    }

    public Map lookInstanceInfo(String id, String viewType, FieldViewAuthType authType) throws Exception {
        InstanceInfo instanceInfo = instanceInfoMapper.findById(id);
        if (null == instanceInfo) {
            throw new InstanceNotExistException();
        }
        Map instanceInfoMap = new HashMap();
        TableSearchParam tableSearchParam = new TableSearchParam();
        tableSearchParam.setInstanceId(id);
        tableSearchParam.setId(instanceInfo.getModelId());
        tableSearchParam.setAuthType(authType);
        tableSearchParam.setFinanceParentId(instanceInfo.getFinanceParentId());
        tableSearchParam.setShowAllField(true);
        //通用实例字段
        tableSearchParam.setTableId(ViewTypeEnum.financeView.getName().equals(viewType) ? TableIdEnum.financeModel.getCode() : TableIdEnum.instance.getCode());
        TableHeaderAndDataManage dataManage = SpringUtils.getBean(TableHeaderAndDataManage.class);
        List<Map> list = (List<Map>) dataManage.listTableData(tableSearchParam);
        if (CollectionUtils.isNotEmpty(list)) {
            instanceInfoMap = list.get(0);
        }
        instanceInfoMap.put(financeParentId, instanceInfo.getFinanceParentId());
        return instanceInfoMap;
    }


    private Criteria doCriteria(InstanceSearchParam instanceSearchParam) throws Exception {

        String modelId = instanceSearchParam.getModelId();
        Map<String, PropertyInfo> propertyInfos = new HashMap<>();
        //获取模型属性信息
        if (StringUtils.isNotEmpty(modelId)) {
            CustomModelServiceImpl modelService = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
            ModelInfo modelInfo = modelService.doSelectById(modelId);
            if (modelInfo != null) {
                //获取模型属性信息
                List<PropertyInfo> dbPropertyMap = modelInfo.getPropertyInfoList();
                Map<String, PropertyInfo> collect = dbPropertyMap.stream().collect(Collectors.toMap(s -> s.getId(), s -> s, (
                        value1, value2) -> {
                    return value2;
                }));
                propertyInfos.putAll(collect);
                instanceSearchParam.addSubCondition(CMDBTool.getFieldName(InstanceInfo::getModelId)
                        , new SubCondition(CriteriaOpsType.is.name(), modelId));
            }
        }
        //没有对应模型属性的，获取全部属性
        if (CollectionUtil.isEmpty(propertyInfos)) {
            ModelPropertyServiceImpl propertyService = (ModelPropertyServiceImpl) cmdbServiceManage.getModelService(ModelPropertyServiceImpl.ID);
            List<PropertyInfo> allModelByListShowProperty = propertyService.getAllModelPropertyList();
            Map<String, PropertyInfo> allPropertyMap = allModelByListShowProperty.stream().collect(Collectors.toMap(s -> s.getId(), s -> s, (
                    value1, value2) -> {
                return value2;
            }));
            propertyInfos.putAll(allPropertyMap);
        }

        //生成类成员变量属性map
        Map<String, PropertyInfo> classPropertyInfos = CMDBTool.genSearchPropertyInfo(InstanceInfoExtend.class);
        propertyInfos.putAll(classPropertyInfos);

        //获取参数值对对应属性类型,并生成查询条件
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put(ViewConvertContext.MwuserApiKey, userApi);
        instanceSearchParam.setParam(paramMap);
        Criteria criteria = genCriteria(propertyInfos, instanceSearchParam, InstanceInfo.SearchPrefix, null, prefixFunction -> {
            String newPrefix = resetPrefixFields.contains(prefixFunction.getPropertyName()) ? "" : prefixFunction.getPrefix();
            return newPrefix;
        });

        return criteria;
    }

    /**
     * 重写实例的模糊查询
     *
     * @param keyword
     * @param propertyInfos
     * @param criteriaList
     * @param prefix
     */
    @Override
    protected void keywordCriteria(String keyword, Map<String, PropertyInfo> propertyInfos, List<Criteria> criteriaList, String prefix) {
        for (PropertyInfo propertyInfo : propertyInfos.values()) {
            PropertyType propertyType = propertyInfo.getPropertyType();
            if (propertyInfo.isKeywordSearch()) {
                Map<String, SubCondition> condition = new HashMap<>();
                SubCondition subCondition = new SubCondition(CriteriaOpsType.like.name(), keyword);
                condition.put(propertyInfo.getName(), subCondition);
                if (resetPrefixFields.contains(propertyInfo.getName())) {
                    prefix = "";
                }
                Criteria criteria = propertyType.criteria(propertyInfo, condition, prefix);
                if (null != criteria) {
                    criteriaList.add(criteria);
                }
            }
        }
    }

    /**
     * 获取所有纳管实例
     *
     * @return
     * @throws Exception
     */
    public List<InstanceInfoExtend> getAllMonitorInstanceList(InstanceSearchParam instanceSearchParam) throws Exception {
        instanceSearchParam.addSubCondition(MonitorTypeIdKey
                , new SubCondition(CriteriaOpsType.exist.name(), true));
        instanceSearchParam.addSubCondition(MonitorServerIdKey
                , new SubCondition(CriteriaOpsType.exist.name(), true));
        Criteria criteria = doCriteria(instanceSearchParam);
        List<InstanceInfoExtend> ret = CMDBTool.aggregateAuthorizedList(InstanceInfoExtend.class, instanceInfoMapper, criteria, instanceSearchParam);
        return ret;
    }

    public List<InstanceInfo> selectListByQuery(Query query) throws Exception {
        query.addCriteria(CriteriaWrapper.where(InstanceInfo::getDelFlag).is(false));
        List<InstanceInfo> ret = instanceInfoMapper.find(query);
        return ret;
    }

    List<InstanceInfo> selectAll() throws Exception {
        Query query = new Query(CriteriaWrapper.where(InstanceInfo::getDelFlag).is(false));
        List<InstanceInfo> ret = instanceInfoMapper.find(query);
        return ret;
    }

    private ModelInfo getModelInfo(Object modelId) {
        CustomModelServiceImpl modelService = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
        ModelInfo modelInfo = modelService.doSelectById(modelId);
        return modelInfo;
    }

    private List<ModelInfo> getModelInfoList(List<String> ids) throws Exception {
        CustomModelServiceImpl modelService = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
        List<ModelInfo> modelInfos = modelService.findByIds(ids);
        return modelInfos;
    }


    public AddAndUpdInstanceContext addAndUpdInstanceValidate(InstanceInfo param, boolean enableAdd) throws Exception {
        batchAddAndUpdInstanceValidate(Arrays.asList(param), enableAdd, null);
        return null;
    }

    public List<AddAndUpdInstanceContext> batchAddAndUpdInstanceValidate(List<InstanceInfo> paramList, boolean enableAdd, BatchAddAndUpdInstanceParam batchAddAndUpdInstanceParam) throws Exception {
        Set<String> modelIds = new HashSet<>();
        List<AddAndUpdInstanceContext> listContext = new ArrayList<>();
        CompoundException instanceParamValidateException = new CompoundException();
        List<AddAndUpdInstanceContext> newContextList = new ArrayList<>();
        MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
        // 查询模型所有父模型
        CustomModelServiceImpl modelService = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
        ModelSearchParam modelSearchParam = new ModelSearchParam();
        modelSearchParam.addSubCondition(CMDBTool.getFieldName(ModelInfo::getFunctionModule), new SubCondition(CriteriaOpsType.in.name(), FunctionModuleEnum.financeReport.getCode()));
        List<ModelInfo> financeParentModelInfos = modelService.getAllModelByParentGroup(modelSearchParam);
        Map<String, ModelInfo> modelId2FinanceParentModelInfoMap = financeParentModelInfos.stream().collect(Collectors.toMap(ModelInfo::getId, item -> item, (o1, o2) -> o1));
        List<String> financeParentModelIds = financeParentModelInfos.stream().map(ModelInfo::getId).toList();
        //获取模型属性信息
        if (CollectionUtils.isNotEmpty(paramList)) {
            for (InstanceInfo param : paramList) {
                if (!Strings.isNullOrEmpty(param.getModelId())) {
                    modelIds.add(param.getModelId());
                }
            }
            ModelPropertyServiceImpl propertyService = (ModelPropertyServiceImpl) cmdbServiceManage.getModelService(ModelPropertyServiceImpl.ID);
            //获取模型对应的全部属性集合(包含父模型的属性)
            Map<String, List<PropertyInfo>> modelAllPropertyList = propertyService.getModelAllPropertyList(new ArrayList<>(modelIds), null);

            List<ModelInfo> modelInfos = getModelInfoList(new ArrayList<>(modelIds));
            Map<String, ModelInfo> collect = modelInfos.stream().collect(Collectors.toMap(s -> s.getId(), s -> s));
            List<Criteria> uniqueCriterias = new ArrayList<>();
            List<String> ignoreOwnIds = new ArrayList<>();
            List<Map<String, String>> uniqueNameList = new ArrayList<>();
            Set<String> uniqueNameSet = new HashSet<>();

            StringBuffer checkMessage;
            Iterator<InstanceInfo> iterator = paramList.iterator();
            InstanceInfo param;
            while (iterator.hasNext()) {
                param = iterator.next();
                checkMessage = new StringBuffer();
                Map dataMap = param.getData();
                if (param.getUsers() != null) {
                    dataMap.put(CMDBTool.getFieldName(InstanceInfo::getUsers), param.getUsers());
                }
                if (param.getOrgs() != null) {
                    dataMap.put(CMDBTool.getFieldName(InstanceInfo::getOrgs), param.getOrgs());
                }
                if (param.getOrgIds() != null) {
                    dataMap.put(CMDBTool.getFieldName(InstanceInfo::getOrgIds), param.getOrgIds());
                }
                if (param.getGroups() != null) {
                    dataMap.put(CMDBTool.getFieldName(InstanceInfo::getGroups), param.getGroups());
                }
                if (param.getModelId() != null) {
                    dataMap.put(CMDBTool.getFieldName(InstanceInfo::getModelId), param.getModelId());
                }
                if (param.getId() != null) {
                    dataMap.put(CMDBTool.getFieldName(InstanceInfo::getId), param.getId());
                }
                String modelId = param.getModelId();
                ModelInfo modelInfo = collect.get(param.getModelId());
                if (null == modelInfo) {
                    String info = (null == modelId ? "" : modelId);
                    throw new NotFindModelException(info);
                }
                Map<String, Object> data = new HashMap<>();


                List<RecordTrigger> triggers = new ArrayList<>();
                List<PropertyInfo> propertyInfoList = new ArrayList<>();
                if (modelAllPropertyList != null && modelAllPropertyList.containsKey(modelId)) {
                    propertyInfoList = modelAllPropertyList.get(modelId);
                }
                String financeParentModelId = param.getFinanceParentId();
                filterFinanceParentModelProperty(propertyInfoList, modelId2FinanceParentModelInfoMap.get(financeParentModelId), financeParentModelIds);
                List<String> uniqueFlagList = new ArrayList<>();
                //按照属性信息来循环处理,保证只会输入模型中定义的属性
                for (PropertyInfo propertyInfo : propertyInfoList) {
                    //导入修改不可以变更的字段属性(创建人，创建时间，修改人，修改时间，模型分组，模型名称)
                    if (dataAuthInfoList.contains(propertyInfo.getId())) {
                        continue;
                    }
                    //是否需要校验
                    boolean isFlag = true;
                    if (propertyInfo.getEnableShow() != null && !propertyInfo.getEnableShow()) {
                        isFlag = false;
                    }
                    //新增操作，属性无新增权限的忽略
                    if (enableAdd && (propertyInfo.getFieldViewAuthTypes() != null && !propertyInfo.getFieldViewAuthTypes().contains(FieldViewAuthType.add))) {
                        isFlag = false;
                    }
                    //修改操作，属性无修改权限的忽略
                    if (!enableAdd && (propertyInfo.getFieldViewAuthTypes() != null && !propertyInfo.getFieldViewAuthTypes().contains(FieldViewAuthType.upd))) {
                        isFlag = false;
                    }
                    PropertyTypeRef propertyTypeRef = propertyInfo.getPropertyTypeRef();
                    PropertyType propertyType = PropertyTypeManage.getPropertyType(propertyTypeRef.getTypeId());
                    propertyType.init(userApi);

                    boolean containsFlag = dataMap.containsKey(propertyInfo.getId());
                    //批量导入修改时，没有对应的属性字段，直接跳过不校验
                    if (!containsFlag && !enableAdd && batchAddAndUpdInstanceParam != null) {
                        continue;
                    }
                    PropertyNameValue propertyNameValue = propertyInfo.getValue(dataMap);
                    Object value = null;

                    //生成触发器,目前只支持了时间触发器
                    if (null != propertyNameValue) {
                        RecordTrigger trigger = getMwCmdbTriggerManager().getRecordTriggerByModelName(modelInfo.getModelName(), propertyInfo);
                        if (null != trigger) {
                            triggers.add(trigger);
                        }
                        value = propertyNameValue.getValue();
                    }
                    //资产编码逻辑
                    //1：经费模型新增时，自动新增；修改为金融元父模型时(判断父模型id是否有值)，资产编码取金融元父模型的
                    //资产编码有属性存在，如果没有数据，需要自动生成
                    if (propertyInfo.getEnableShow() != null && propertyInfo.getEnableShow() && mwAssetCodingKey.equals(propertyInfo.getId())) {
                        String modelCodeId = Strings.isNullOrEmpty(financeParentModelId) ? modelId : financeParentModelId;
                        String assetsCodingPrefix = getModelCodeCheck(modelCodeId);
                        //校验模型code
                        if (Strings.isNullOrEmpty(assetsCodingPrefix)) {
                            ModelCodeValErrorException modelCodeNoFindException = new ModelCodeValErrorException(modelCodeId);
                            //是否资产部分导入
                            if (batchAddAndUpdInstanceParam != null && batchAddAndUpdInstanceParam.isPartiallyFlag()) {
                                checkMessage.append(messageSource.getMessage(modelCodeNoFindException.getMessageKey(), modelCodeNoFindException.getArgs(), LocaleContextHolder.getLocale())).append(";");
                                continue;
                            } else {
                                throw modelCodeNoFindException;
                            }
                        }
                        //如果是只读限制，后台自动生成
                        //没有只读限制，excel导入中有数据，就取数据（获取最大值设置到redis中），没有的就自动生成
                        if (null != propertyInfo.getFieldAuthTypes() && propertyInfo.getFieldAuthTypes().contains(FieldAuthType.readonly)) {
                            //只读限制
                            if (enableAdd) {
                                propertyNameValue = new PropertyNameValue(propertyInfo.getId(), assetsCodingPrefix);
                                //通过校验后，设置自增资产编码
                                param.setDeviceCodeFlag(true);
                            }
                        } else {
                            //没有只读限制，资产实物标签号可以输入

                            //新增
                            //有值，判断是否合规
                            if (enableAdd) {
                                if (!Strings.isNullOrEmpty(strValueConvert(value))) {
                                    //不合规
                                    if (!checkModelCodeMatch(assetsCodingPrefix, strValueConvert(value))) {
                                        ModelCodeValErrorException modelCodeValErrorException = new ModelCodeValErrorException(modelCodeId);
                                        //是否资产部分导入
                                        if (batchAddAndUpdInstanceParam != null && batchAddAndUpdInstanceParam.isPartiallyFlag()) {
                                            checkMessage.append(messageSource.getMessage(modelCodeValErrorException.getMessageKey(), modelCodeValErrorException.getArgs(), LocaleContextHolder.getLocale())).append(";");
                                        } else {
                                            throw modelCodeValErrorException;
                                        }
                                    } else {
                                        //合规，判断是否包含xxxxxx数据，有，标识为假性数据，没有，且长度为24位
                                        if (strValueConvert(value).contains("xxxxxx") || strValueConvert(value).length() != 24) {
                                            //假性数据，错误数据，自增处理
                                            propertyNameValue = new PropertyNameValue(propertyInfo.getId(), assetsCodingPrefix);
                                            //通过校验后，设置自增资产编码
                                            param.setDeviceCodeFlag(true);
                                        }
                                    }
                                } else {
                                    //无值，自增
                                    propertyNameValue = new PropertyNameValue(propertyInfo.getId(), assetsCodingPrefix);
                                    //通过校验后，设置自增资产编码
                                    param.setDeviceCodeFlag(true);
                                }

                            } else {
                                //修改时不合规
                                if (!checkModelCodeMatch(assetsCodingPrefix, strValueConvert(value)) || strValueConvert(value).contains("xxxxxx") || strValueConvert(value).length() != 24) {
                                    //无值，自增
                                    propertyNameValue = new PropertyNameValue(propertyInfo.getId(), assetsCodingPrefix);
                                    //通过校验后，设置自增资产编码
                                    param.setDeviceCodeFlag(true);
                                }
                            }
                        }

                    }
                    //本币原值有属性存在，如果没有数据，需要自动生成
                    if (propertyInfo.getEnableShow() != null && propertyInfo.getEnableShow() && mwOriginalValue.equals(propertyInfo.getId())) {
                        if (null == value) {
                            value = new BigDecimal("0");
                            propertyNameValue = new PropertyNameValue(propertyInfo.getId(), value);
                        }
                    }

                    try {
                        if (isFlag) {
                            //验证输入值是否符合属性要求,包括是否必输
                            propertyInfo.validateValue(value);

                            //验证是否符合类型要求
                            propertyType.validateValue(value, propertyTypeRef);

                            //更新情况下,验证是否只读
                            if (!enableAdd && null != propertyInfo.getFieldAuthTypes()
                                    && propertyInfo.getFieldAuthTypes().contains(FieldAuthType.readonly)
                                    && param.getData().containsKey(propertyInfo.getId())
                            ) {
                                throw new InputReadonlyException(new Object[]{propertyNameValue.getName()});
                            }

                            //产生唯一性判断条件
                            Set<FieldAuthType> fieldAuthTypes = propertyInfo.getFieldAuthTypes();
                            if (null != fieldAuthTypes && fieldAuthTypes.contains(FieldAuthType.unique) && !Strings.isNullOrEmpty(strValueConvert(value))) {
                                if (propertyNameValue != null) {
                                    Map<String, String> uniqueNameMap = new HashMap<>();
                                    uniqueNameMap.put(propertyNameValue.getName(), propertyInfo.getName() + UniqueAlertSep + propertyNameValue.getValue());
                                    //唯一性标识集合
                                    uniqueFlagList.add(propertyInfo.getName() + UniqueAlertSep + propertyNameValue.getValue());
                                    uniqueNameList.add(uniqueNameMap);
                                    Criteria criteria = propertyType.criteria(CriteriaOpsType.is, propertyNameValue.getName(), value, SearchPrefix);
                                    if (null != criteria) {
                                        uniqueCriterias.add(criteria);
                                        uniqueNameSet.add(criteria.getKey());
                                    }
                                    //更新情况下,忽略本体数据
                                    if (!enableAdd) {
                                        ignoreOwnIds.add(param.getId());
                                    }
                                }
                            }
                        }
                    } catch (BusinessException e) {
                        checkMessage.append(messageSource.getMessage(e.getMessageKey(), e.getArgs(), LocaleContextHolder.getLocale())).append(";");
                        if ((batchAddAndUpdInstanceParam != null && !batchAddAndUpdInstanceParam.isPartiallyFlag())) {
                            instanceParamValidateException.addInstanceValidateException(e);
                        }
                    }
                    Object obj = null;
                    if (specialHandleList.contains(propertyInfo.getId())) {
                        obj = propertyType.convertValue(propertyInfo.getId(), value);
                    } else {
                        obj = propertyType.convertValue(value);
                    }
                    //为了实现编辑修改时，页面上清除数据导致字段值为null(map不加载value为null的数据)，默认设置为空字段，通过不同的属性类型，更新去除字段值得操作
                    if ((null != obj || (strValueConvert(value).equals("") && !enableAdd)) && propertyNameValue != null) {
                        data.put(propertyNameValue.getName(), obj);
                    }
                }
                if (checkMessage.length() > 0 && batchAddAndUpdInstanceParam != null && batchAddAndUpdInstanceParam.isPartiallyFlag()) {
                    if (batchAddAndUpdInstanceParam.getCheckFailedList() == null) {
                        batchAddAndUpdInstanceParam.setCheckFailedList(new ArrayList<>());
                    }
                    InstanceCheckVo instanceCheckVo = new InstanceCheckVo();
                    instanceCheckVo.setInstanceName(param.getInstanceName());
                    instanceCheckVo.setModelId(modelId);
                    instanceCheckVo.setFinanceParentModelId(financeParentModelId);
                    instanceCheckVo.setErrorMessage(checkMessage.toString());
                    instanceCheckVo.setRowIndex(param.getData().getOrDefault(mwExcelRowIndex, "").toString());
                    batchAddAndUpdInstanceParam.getCheckFailedList().add(instanceCheckVo);
                    iterator.remove();
                    continue;
                }
                AddAndUpdInstanceContext context = AddAndUpdInstanceContext.builder()
                        .instanceInfo(param)
                        .dataBefore(dataMap)
                        .data(data)
                        .uniqueFlagList(uniqueFlagList)
                        .modelInfo(modelInfo)
                        .triggers(triggers).build();
                listContext.add(context);
            }
            Set<String> uniqueAlert = new HashSet<>();
            if (enableAdd) {//资产新增时校验
                //检查并设置设备指纹信息
                DataUniqueException dataUniqueException = CMDBCommonUtil.validateUniqueDeviceByDeviceCode(paramList
                        , scanEngineService, this, assetsInterfaceMapper, mwEngineManageService);

                if (null != dataUniqueException) {
                    instanceParamValidateException.addInstanceValidateException(dataUniqueException);
                }
            }

            //验证唯一性
            if (uniqueCriterias.size() > 0) {
                Query query = new Query(CriteriaWrapper.where(InstanceInfo::getDelFlag).is(false));
                query.addCriteria(new Criteria().orOperator(uniqueCriterias));
                List<InstanceInfo> countList = instanceInfoMapper.find(query);
                //如果是修改，忽略本体的唯一性校验
                if (!enableAdd && CollectionUtils.isNotEmpty(ignoreOwnIds)) {
                    countList = countList.stream().filter(s -> !ignoreOwnIds.contains(s.getId())).collect(Collectors.toList());
                }

                TableSearchParam tableDataParam = new TableSearchParam();
                tableDataParam.setTableId(TableIdEnum.customInstance.getCode());
                tableDataParam.setEnableMonitorStatus(false);
                tableDataParam.setShowAllField(true);
                ViewConvertContext viewConvertContext = new ViewConvertContext();
                viewConvertContext.put(serviceManage, cmdbServiceManage);
                viewConvertContext.setType(checkView);
                ViewManager viewManager = SpringUtils.getBean(ViewManager.class);
                tableDataParam.setPage(null);
                List<Map<String, Object>> objList = (List<Map<String, Object>>) viewManager.getListViewObject(countList, InstanceRelationInfo.class, tableDataParam, viewConvertContext);

                Map<String, String> userInfo = new HashMap<>();
                Map<String, String> orgInfo = new HashMap<>();
                Map<String, String> groupInfo = new HashMap<>();
                Map<String, PropertyInfo> propertyInfoMap = new HashMap<>();
                for (String modelIdStr : modelIds) {
                    List<PropertyInfo> propertyInfoList = modelAllPropertyList.get(modelIdStr);
                    propertyInfoMap.putAll(propertyInfoList.stream().collect(Collectors.toMap(s -> s.getId(), s -> s, (
                            value1, value2) -> {
                        return value2;
                    })));
                }


                if (countList.size() > 0) {
                    // 唯一字段约束
                    Map<String, Set<String>> unitKey2ValueMap = new HashMap<>();
                    Set<Long> userIds = new HashSet<>();
                    Set<Long> orgIds = new HashSet<>();
                    Set<Long> groupIds = new HashSet<>();


                    //组合唯一性校验提示信息
                    for (InstanceInfo instanceInfo : countList) {
                        String modelId = instanceInfo.getModelId();
                        for (Map<String, String> m : uniqueNameList) {
                            m.forEach((k, v) -> {
                                //字段id
                                String fieldId = k;
                                //提示信息
                                String inputValueOld = "";
                                if (v.split(":").length > 0) {
                                    // 非必填唯一字段未填值时不校验
                                    if (v.split(UniqueAlertSep).length == 1 || !StringUtils.isNotEmpty(v.split(UniqueAlertSep)[1])) {
                                        return;
                                    }
                                    //数据库查询的重复实例和唯一校验条件比较判断，
                                    inputValueOld = v.split(UniqueAlertSep)[1];
                                }
                                PropertyInfo propertyInfo = propertyInfoMap.get(fieldId);
                                if (propertyInfo != null) {
                                    boolean userFlag = PropertyTypeUser.ID.equals(propertyInfo.getPropertyTypeRef().getTypeId());
                                    boolean orgFlag = PropertyTypeOrg.ID.equals(propertyInfo.getPropertyTypeRef().getTypeId());
                                    boolean groupFlag = PropertyTypeGroup.ID.equals(propertyInfo.getPropertyTypeRef().getTypeId());
                                    if (userFlag) {
                                        List userIdList = (List) JSONArray.parseArray(v.split(UniqueAlertSep)[1]);
                                        userIds.addAll(userIdList);
                                    }
                                    if (orgFlag) {
                                        List orgIdListAll = (List) JSONArray.parseArray(v.split(UniqueAlertSep)[1]);
                                        for (Object objOrg : orgIdListAll) {
                                            if (objOrg != null && objOrg instanceof List) {
                                                List orgIdList = (List) objOrg;
                                                orgIds.addAll(orgIdList);
                                            }
                                        }
                                    }
                                    if (groupFlag) {
                                        List groupIdList = (List) JSONArray.parseArray(v.split(UniqueAlertSep)[1]);
                                        groupIds.addAll(groupIdList);
                                    }
                                }
                            });
                        }
                    }
                    //获取权限数据
                    List<OrgDTO> orgDTOS = userApi.getAllOrg();
                    List<GroupDTO> groupDTOS = userApi.getGroupListByIds(new ArrayList<>(groupIds));
                    List<MwUser> mwUsers = userApi.getUsersByUserIds(new ArrayList<>(userIds));
                    //数据转换
                    if (null != mwUsers) {
                        for (MwUser mwUser : mwUsers) {
                            userInfo.put(mwUser.getId().toString(), mwUser.getNickName());
                        }
                    }
                    if (null != groupDTOS) {
                        for (GroupDTO groupDTO : groupDTOS) {
                            groupInfo.put(groupDTO.getId().toString(), groupDTO.getGroupName());
                        }
                    }
                    Set<Long> longSet = orgDTOS.stream().map(s -> s.getId()).collect(Collectors.toSet());
                    for (Object orgId : orgIds) {
                        Map<Long, String> parentInfoMap = getParentInfoMap(longSet, orgDTOS, longValueConvert(orgId));
                        orgInfo.put(orgId.toString(), parentInfoMap.get(longValueConvert(orgId)));
                    }


                    //组合唯一性校验提示信息
                    for (Map<String, Object> instanceInfoMap : objList) {
                        for (Map<String, String> m : uniqueNameList) {
                            m.forEach((k, v) -> {
                                //字段id
                                String fieldId = k;
                                //提示信息
                                String val = v;
                                String tipVal = v;
                                //提示信息
                                if (v.split(":").length > 0) {
                                    // 非必填唯一字段未填值时不校验
                                    if (v.split(UniqueAlertSep).length == 1 || !StringUtils.isNotEmpty(v.split(UniqueAlertSep)[1])) {
                                        return;
                                    }
                                }
                                boolean userFlag = false;
                                boolean orgFlag = false;
                                boolean groupFlag = false;
                                PropertyInfo propertyInfo = propertyInfoMap.get(fieldId);
                                String authName = "";
                                if (propertyInfo != null) {
                                    userFlag = PropertyTypeUser.ID.equals(propertyInfo.getPropertyTypeRef().getTypeId());
                                    orgFlag = PropertyTypeOrg.ID.equals(propertyInfo.getPropertyTypeRef().getTypeId());
                                    groupFlag = PropertyTypeGroup.ID.equals(propertyInfo.getPropertyTypeRef().getTypeId());

                                    if (userFlag && userInfo != null) {
                                        List authIdList = (List) JSONArray.parseArray(tipVal.split(UniqueAlertSep)[1]);
                                        for (Object obj : authIdList) {
                                            if (userInfo.containsKey(strValueConvert(obj))) {
                                                authName += userInfo.get(strValueConvert(obj)) + ",";
                                            }
                                        }
                                    }
                                    if (orgFlag && orgInfo != null) {
                                        List authIdList = (List) JSONArray.parseArray(tipVal.split(UniqueAlertSep)[1]);
                                        for (Object obj : authIdList) {
                                            if (obj != null && obj instanceof List) {
                                                List orgList2 = (List) obj;
                                                for (Object objs : orgList2) {
                                                    if (groupInfo.containsKey(strValueConvert(objs))) {
                                                        authName += groupInfo.get(strValueConvert(objs)) + ",";
                                                    }
                                                }
                                            }
                                        }
                                    }
                                    if (groupFlag && groupInfo != null) {
                                        List authIdList = (List) JSONArray.parseArray(tipVal.split(UniqueAlertSep)[1]);
                                        for (Object obj : authIdList) {
                                            if (groupInfo.containsKey(strValueConvert(obj))) {
                                                authName += groupInfo.get(strValueConvert(obj)) + ",";
                                            }
                                        }
                                    }
                                }
                                String newTipVal = tipVal;
                                if (!Strings.isNullOrEmpty(authName)) {
                                    newTipVal = tipVal.replace(tipVal.split(UniqueAlertSep)[1], authName);
                                }
                                if (val.split(":").length > 0) {
                                    // 非必填唯一字段未填值时不校验
                                    if (val.split(UniqueAlertSep).length == 1 || !StringUtils.isNotEmpty(val.split(UniqueAlertSep)[1])) {
                                        return;
                                    }
                                    //数据库查询的重复实例和唯一校验条件比较判断，
                                    String inputValue = val.split(UniqueAlertSep)[1];
                                    if (instanceInfoMap.containsKey(fieldId) && instanceInfoMap.get(fieldId) != null && strValueConvert(instanceInfoMap.get(fieldId)).equals(inputValue)) {
                                        uniqueAlert.add(newTipVal);
                                        if (!unitKey2ValueMap.containsKey(k)) {
                                            unitKey2ValueMap.put(k, new HashSet<>());
                                        }
                                        unitKey2ValueMap.get(k).add(v);
                                    }
                                }
                            });
                        }

                        for (Criteria criteria : uniqueCriterias) {
                            String key = criteria.getKey();
                            if (StringUtils.isNotEmpty(key) && !uniqueNameSet.contains(key)) {
                                Object value = instanceInfoMap.get(key);
                                if (null != value) {
                                    String message = key + UniqueAlertSep + value.toString();
                                    uniqueAlert.add(message);
                                    if (!unitKey2ValueMap.containsKey(key)) {
                                        unitKey2ValueMap.put(key, new HashSet<>());
                                    }
                                    unitKey2ValueMap.get(key).add(value.toString());
                                }

                            }
                        }
                    }

                    if (batchAddAndUpdInstanceParam != null && batchAddAndUpdInstanceParam.isPartiallyFlag()) {
                        // 支持部分插入场景 过滤出校验失败的数据
                        Iterator<AddAndUpdInstanceContext> addAndUpdInstanceContextIterator = listContext.iterator();
                        AddAndUpdInstanceContext context;
                        InstanceInfo instanceInfo;
                        String uniqueCheckMessage;
                        while (addAndUpdInstanceContextIterator.hasNext()) {
                            context = addAndUpdInstanceContextIterator.next();
                            instanceInfo = context.getInstanceInfo();
                            uniqueCheckMessage = getUniqueCheckMessage(unitKey2ValueMap, instanceInfo, messageSource);
                            if (StringUtils.isNotEmpty(uniqueCheckMessage)) {
                                if (batchAddAndUpdInstanceParam.getCheckFailedList() == null) {
                                    batchAddAndUpdInstanceParam.setCheckFailedList(new ArrayList<>());
                                }
                                InstanceCheckVo instanceCheckVo = new InstanceCheckVo();
                                instanceCheckVo.setInstanceName(instanceInfo.getInstanceName());
                                instanceCheckVo.setErrorMessage(uniqueCheckMessage);
                                instanceCheckVo.setModelId(instanceInfo.getModelId());
                                instanceCheckVo.setFinanceParentModelId(instanceInfo.getFinanceParentId());
                                instanceCheckVo.setRowIndex(instanceInfo.getData().getOrDefault(mwExcelRowIndex, "").toString());
                                batchAddAndUpdInstanceParam.getCheckFailedList().add(instanceCheckVo);
                                addAndUpdInstanceContextIterator.remove();
                            }
                        }
                        newContextList = listContext;
                    } else {
                        //唯一性校验过滤数据
                        for (AddAndUpdInstanceContext context : listContext) {
                            if (CollectionUtils.isNotEmpty(context.getUniqueFlagList()) && !uniqueAlert.containsAll(context.getUniqueFlagList())) {
                                newContextList.add(context);
                            }
                        }
                        if (uniqueAlert != null && uniqueAlert.size() > 0) {
                            instanceParamValidateException.addInstanceValidateException(new DataUniqueException(new Object[]{uniqueAlert}));
                        }
                    }
                } else {
                    newContextList = listContext;
                }
            } else {
                newContextList = listContext;
            }
            addAndUpdInstanceContextThreadLocal.set(newContextList);
        }
        if (batchAddAndUpdInstanceParam != null) {
            batchAddAndUpdInstanceParam.setSuccessList(listContext.stream().map(item -> SerializationUtils.clone(item.getInstanceInfo())).toList());
            paramList.clear();
            paramList.addAll(batchAddAndUpdInstanceParam.getSuccessList());
        }
        if (instanceParamValidateException.hasException()) {
            throw instanceParamValidateException;
        }
        return newContextList;
    }


    public static Map<Long, String> getParentInfoMap(Set<Long> orgIds, List<OrgDTO> orgDtos, Long id) {
        List<Long> parentIds = new ArrayList<>();
        List<String> parentNames = new ArrayList<>();
        findParentInfo(orgIds, orgDtos, id, parentIds, parentNames);

        // 反转列表顺序
        Collections.reverse(parentIds);
        Collections.reverse(parentNames);

        // 构造结果 Map
        Map<Long, String> resultMap = new HashMap<>();
        resultMap.put(id, String.join("/", parentNames));

        return resultMap;
    }

    private static void findParentInfo(Set<Long> orgIds, List<OrgDTO> orgDtos, Long id, List<Long> parentIds, List<String> parentNames) {
        Optional<OrgDTO> currentOrg = orgDtos.stream().filter(org -> org.getId().equals(id)).findFirst();
        if (currentOrg.isPresent() && currentOrg.get().getPid() != null) {
            if (orgIds.contains(currentOrg.get().getId())) {
                parentIds.add(currentOrg.get().getId());
                parentNames.add(currentOrg.get().getOrgName());
                findParentInfo(orgIds, orgDtos, currentOrg.get().getPid(), parentIds, parentNames);
            }
        }
    }


    public void filterFinanceParentModelProperty(List<PropertyInfo> propertyInfoList, ModelInfo financeParentModelInfo, List<String> financeParentModelIds) throws Exception {
        Iterator<PropertyInfo> iterator = propertyInfoList.iterator();
        PropertyInfo propertyInfo;
        while (iterator.hasNext()) {
            propertyInfo = iterator.next();
            // 未指定金融元父模型 过滤所有金融元父模型字段
            if (financeParentModelInfo == null) {
                if (financeParentModelIds.contains(propertyInfo.getModelId())) {
                    iterator.remove();
                }
            } else {
                // 指定了金融元父模型 过滤其它金融元父模型字段
                if (financeParentModelIds.contains(propertyInfo.getModelId()) &&
                        !financeParentModelInfo.getId().equals(propertyInfo.getModelId())) {
                    iterator.remove();
                }
            }
        }
    }

    private String getUniqueCheckMessage(Map<String, Set<String>> unitKey2ValueMap, InstanceInfo instanceInfo, MessageSource messageSource) throws InvocationTargetException, IllegalAccessException {
        Map<String, Object> data = instanceInfo.getData();
        Map<String, Object> instanceInfoMap = getFieldInfoToMap(instanceInfo, Arrays.asList(CMDBTool.getFieldName(InstanceInfo::getData)));
        instanceInfoMap.putAll(data);
        StringBuffer errorMessage = new StringBuffer();
        for (Map.Entry<String, Object> entry : instanceInfoMap.entrySet()) {
            if (unitKey2ValueMap.containsKey(entry.getKey()) && entry.getValue() != null) {
                String matchMessage = getMatchMessage(unitKey2ValueMap.get(entry.getKey()), entry.getValue().toString());
                if (matchMessage != null) {
                    errorMessage.append(messageSource.getMessage("data-unique-error",
                            new Object[]{matchMessage}, LocaleContextHolder.getLocale()));
                }
            }
        }
        return errorMessage.toString();
    }

    private String getMatchMessage(Set<String> valueSet, String value) {
        for (String item : valueSet) {
            if (item.contains(":") && item.substring(item.indexOf(":") + 1).equals(value)) {
                return item;
            } else if (item.equals(value)) {
                return item;
            }
        }
        return null;
    }

    private boolean batchAddAndUpdInstance(List<InstanceInfo> list, boolean enableAdd, Consumer<InstanceInfoAddUpdContext> instanceInfoConsumer) throws Exception {
        return batchAddAndUpdInstanceHandle(list, enableAdd, instanceInfoConsumer, null);
    }

    private boolean batchAddAndUpdInstance(List<InstanceInfo> list, boolean enableAdd, Consumer<InstanceInfoAddUpdContext> instanceInfoConsumer, BatchAddAndUpdInstanceParam batchAddAndUpdInstanceParam) throws Exception {
        return batchAddAndUpdInstanceHandle(list, enableAdd, instanceInfoConsumer, batchAddAndUpdInstanceParam);
    }

    private boolean batchAddAndUpdInstanceHandle(List<InstanceInfo> list, boolean enableAdd, Consumer<InstanceInfoAddUpdContext> instanceInfoConsumer, BatchAddAndUpdInstanceParam batchAddAndUpdInstanceParam) throws Exception {
        //验证并组装信息,流程拦截时,会执行一次验证并把验证信息保存
        Map<InstanceInfo, AddAndUpdInstanceContext> instanceInfo2DataContextMap = new HashMap<>();
        List<AddAndUpdInstanceContext> dataContextList = addAndUpdInstanceContextThreadLocal.get();
        //修改时重新校验
        if (null == dataContextList || !enableAdd) {
            dataContextList = batchAddAndUpdInstanceValidate(list, enableAdd, batchAddAndUpdInstanceParam);
        }
        addAndUpdInstanceContextThreadLocal.remove();
        InstanceInfoAddUpdContext context = new InstanceInfoAddUpdContext();
        List<InstanceInfo> manageInstanceList = new ArrayList<>();
        List<InstanceInfo> unManageInstanceList = new ArrayList<>();
        List<InstanceInfo> webMonitorAddInstanceList = new ArrayList<>();
        List<InstanceInfo> webMonitorUpdateInstanceList = new ArrayList<>();
        String webMonitorModelId = SpringUtils.getPropertiesValue("base.webMonitor.modelId");

        List<MwCmdbTrigger> mwCmdbTriggers = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(dataContextList)) {
            log.info("dataContextList::" + dataContextList);
            for (AddAndUpdInstanceContext dataContext : dataContextList) {
                InstanceInfo instanceInfo = dataContext.getInstanceInfo();
                //设置转换之后的属性信息
                instanceInfo.setData(dataContext.getData());
                //数据组装、获取功能权限数据
                List<String> functionModule = instanceParamConvert(instanceInfo, dataContext.getModelInfo());
                //配置业务系统外部关联对象Id路径
                configRelationPath(instanceInfo);

                //勾选运维监控，添加资产纳管
                if (functionModule.contains(enableMonitor.getCode())) {
                    //资产新增时，勾选了纳管直接进入纳管操作
                    if (enableAdd) {
                        //获取InstanceId,纳管时添加宏值使用
                        if (Strings.isNullOrEmpty(instanceInfo.getId())) {
                            instanceInfo.setId(strValueConvert(moduleIDManager.getID(IDModelType.Model)));
                        }
                        instanceInfo.setItemAssetsStatus(ABNORMAL.getName());
                        manageInstanceList.add(instanceInfo);
                    } else {
                        //修改时，勾选了纳管，需要判断之前的资产状态，如果是未纳管，表示本次修改需要纳管操作
                        if (UNKNOWN.getName().equals(instanceInfo.getItemAssetsStatus())) {
                            manageInstanceList.add(instanceInfo);
                        } else {
                            unManageInstanceList.add(instanceInfo);
                        }
                    }
                } else {
                    instanceInfo.setItemAssetsStatus(UNKNOWN.getName());
                    unManageInstanceList.add(instanceInfo);
                }
                // web监测实例 资产新增时,在zabbix上创建web监测
                if (StringUtils.equals(webMonitorModelId, instanceInfo.getModelId())) {
                    if (enableAdd) {
                        webMonitorAddInstanceList.add(instanceInfo);
                    } else {
                        webMonitorUpdateInstanceList.add(instanceInfo);
                    }
                }

                //instanceInfo与recordTriggers对应存入Map
                instanceInfo2DataContextMap.put(instanceInfo, dataContext);
            }
        }
        CopyOnWriteArrayList<String> assetsCodeCacheAllList = new CopyOnWriteArrayList();
        //资产新增时，进行纳管操作
        //批量纳管
        MonitorModuleServiceImpl monitorModuleService = new MonitorModuleServiceImpl();
        if (CollectionUtils.isNotEmpty(manageInstanceList)) {
            monitorModuleService.batchHandle(manageInstanceList);
        }
        // web监测数据处理
        dealWithWebMonitorInstance(webMonitorAddInstanceList, webMonitorUpdateInstanceList);
        manageInstanceList.addAll(unManageInstanceList);
        if (CollectionUtils.isNotEmpty(manageInstanceList)) {
            Map<String, List<InstanceInfo>> newMap = new HashMap<>();
            //新增修改时，都要处理实物标签号
//            if (enableAdd) {
            //先过滤掉实例标签号为空的数据，在按照对应的模型id(或金融元父模型Id)分组
            //获取每个分组中，最大的实物标签Id，将最大值设置到对应的redis缓存中，如果最大值大于缓存值，设置，小于则不设置

            List<InstanceInfo> collect = manageInstanceList.stream().filter(s -> s.isDeviceCodeFlag()).collect(Collectors.toList());


            Map<String, List<InstanceInfo>> FinanceParentAssetsCodeMap = collect.stream().filter(s -> !Strings.isNullOrEmpty(s.getAssetsCodeKey()) && !Strings.isNullOrEmpty(s.getFinanceParentId())).collect(Collectors.groupingBy(s -> s.getFinanceParentId()));
            if (FinanceParentAssetsCodeMap != null) {
                newMap.putAll(FinanceParentAssetsCodeMap);
            }
            //新增实例时，批量设置资产编码code
            Map<String, List<InstanceInfo>> modelInfoAssetsCodeMap = collect.stream().filter(s -> !Strings.isNullOrEmpty(s.getAssetsCodeKey()) && Strings.isNullOrEmpty(s.getFinanceParentId())).collect(Collectors.groupingBy(s -> s.getModelId()));
            if (modelInfoAssetsCodeMap != null) {
                newMap.putAll(modelInfoAssetsCodeMap);
            }
            for (Map.Entry<String, List<InstanceInfo>> entry : newMap.entrySet()) {
                List<InstanceInfo> instanceInfos = entry.getValue();
                InstanceInfo maxAssetsCode = instanceInfos.stream().max(Comparator.comparing(s -> strValueConvert(s.getAssetsCodeKey()))).get();
                String assetsCodeKey = maxAssetsCode.getAssetsCodeKey();
                int length = assetsCodeKey.length();
                if (length > 7) {
                    String deviceCodeByAssetsCode = getDeviceCodeByAssetsCode(assetsCodeKey);
                    int assetCodeVal = intValueConvert(assetsCodeKey.substring(length - 6, length));
                    setRedisMaxValByAssetCode(deviceCodeByAssetsCode, assetCodeVal);
                }
            }

            newMap = new HashMap<>();
            Map<String, List<InstanceInfo>> FinanceParentMap = collect.stream().filter(s -> s.isDeviceCodeFlag() && !Strings.isNullOrEmpty(s.getFinanceParentId())).collect(Collectors.groupingBy(s -> s.getFinanceParentId()));
            if (FinanceParentMap != null) {
                newMap.putAll(FinanceParentMap);
            }
            //新增实例时，批量设置资产编码code
            Map<String, List<InstanceInfo>> modelInfoMap = collect.stream().filter(s -> s.isDeviceCodeFlag() && Strings.isNullOrEmpty(s.getFinanceParentId())).collect(Collectors.groupingBy(s -> s.getModelId()));
            if (modelInfoMap != null) {
                newMap.putAll(modelInfoMap);
            }
            //按modelId分组
            for (Map.Entry<String, List<InstanceInfo>> keySet : newMap.entrySet()) {
                if (keySet != null && keySet.getValue() != null && keySet.getValue().size() > 0) {
                    String modelId = keySet.getKey();
                    List<InstanceInfo> instanceInfos = keySet.getValue();
                    int sumNum = instanceInfos.size();
                    if (sumNum > 0) {
                        //按照模型id，获取对应数量的资产编码缓存code
                        List<String> assetsCodeCacheList = getAssetsCodeCacheStr(modelId, sumNum);
                        assetsCodeCacheAllList.addAll(assetsCodeCacheList);
                        for (int x = 0; x < instanceInfos.size(); x++) {
                            InstanceInfo instanceInfo = instanceInfos.get(x);
                            if (instanceInfo.isDeviceCodeFlag()) {
                                //设置对于的code值
                                instanceInfo.setAssetsCodeKey(assetsCodeCacheList.get(x));
                            }
                        }
                    }
                }
            }
//            }

            Long creater = SecurityUtils.getUserId();
            for (InstanceInfo instanceInfo : manageInstanceList) {
                //加密信息
                instanceInfo.encryptInfo();
                instanceInfo.fieldCheckMatch();
                if (enableAdd) {
                    //资产状态默认显示正常，后续使用定时任务更新资产状态
                    CMDBTool.initCreateInfo(instanceInfo, creater);
                } else {
                    CMDBTool.initUpdateInfo(instanceInfo, creater);
                }
                //如果为金融元父模型数据,资产编码，设施标识符自动同步数据，资产编码同步实物标签号；设施标识符同步实物标签号+“-0000000”，需要32位符合金融原上报
                if (!Strings.isNullOrEmpty(instanceInfo.getFinanceParentId()) && !Strings.isNullOrEmpty(instanceInfo.getAssetsCodeKey())) {
                    instanceInfo.setFinanceAssetCodeKey(instanceInfo.getAssetsCodeKey());
                    instanceInfo.setFacilityDescriptorKey(instanceInfo.getAssetsCodeKey() + FacilityDescriptoSuffix);
                }
            }
            if (enableAdd) {
                List<InstanceInfo> instanceInfos = new ArrayList<>();
                try {
                    instanceInfos = (List<InstanceInfo>) instanceInfoMapper.insertAll(manageInstanceList);
                } catch (Exception e) {
                    log.error("instanceInfoMapper.insertAll to fail::", e);
                    //资产新增失败，回收code编码
                    insertAssetsCodeCacheList(assetsCodeCacheAllList);
                }

                context.setRetObj(instanceInfos);
                instanceInfoConsumer.accept(context);
                for (Map.Entry<InstanceInfo, AddAndUpdInstanceContext> entry : instanceInfo2DataContextMap.entrySet()) {
                    if (manageInstanceList.contains(entry.getKey())) {
                        AddAndUpdInstanceContext dataContext = entry.getValue();
                        //生成定时触发器
                        List<RecordTrigger> recordTriggers = dataContext.getTriggers();
                        TriggerContext triggerContext = TriggerContext.builder()
                                .instanceInfo(entry.getKey())
                                .modelInfo(dataContext.getModelInfo())
                                .type(MwCmdbBussinessType.instance)
                                .typeId(entry.getKey().getId()).build();
                        if (null != recordTriggers) {
                            for (RecordTrigger recordTrigger : recordTriggers) {
                                MwCmdbTrigger mwCmdbTrigger = (MwCmdbTrigger) recordTrigger.getTrigger(triggerContext);
                                mwCmdbTrigger.setBussinessId(entry.getKey().getId());
                                mwCmdbTriggers.add(mwCmdbTrigger);
                            }
                        }
                    }
                }
                //批量更新执行属性中的触发器
                if (!mwCmdbTriggers.isEmpty()) {
                    log.info("批量更新执行属性中的触发器");
                    getMwCmdbTriggerManager().batchAddTrigger(mwCmdbTriggers);
                }
            } else {//页面编辑修改实例，只能单个修改
                if (CollectionUtils.isNotEmpty(manageInstanceList)) {
                    //batchAddAndUpdInstanceParam不为null，表示批量导入修改
                    boolean isIgnoreNull = true;
                    if (batchAddAndUpdInstanceParam != null) {
                        isIgnoreNull = false;
                    }
                    List<Pair<Query, Update>> updateList = new ArrayList<>();
                    log.info("编辑接口参数打印::" + manageInstanceList);
                    //UNORDERED是异步执行，有错误跳过继续执行；ORDERED时有序执行，遇到错误终止
                    BulkOperations operations = instanceInfoMapper.bulkOps(BulkOperations.BulkMode.UNORDERED, InstanceInfo.class);
                    for (InstanceInfo instanceInfo : manageInstanceList) {
                        Pair<Query, Update> queryUpdatePair = convertUpdateByInstance(instanceInfo, isIgnoreNull);
                        operations.updateMulti(queryUpdatePair.getFirst(), queryUpdatePair.getSecond());
                    }
                    log.info(new Date() + "::updateList::" + updateList);
                    operations.execute();
                    context.setRetBoolean(true);
                    instanceInfoConsumer.accept(context);
                }
            }

        }
        log.info("批量新增更新完成!");
        return true;
    }

    private void dealWithWebMonitorInstance(List<InstanceInfo> webMonitorAddInstanceList, List<InstanceInfo> webMonitorUpdateInstanceList) throws Exception {
        if (CollectionUtils.isNotEmpty(webMonitorAddInstanceList)) {
            // 按照监控服务器分组调用
            Map<Integer, List<InstanceInfo>> serverId2InstanceListMap = webMonitorAddInstanceList.stream().filter(item -> item.getMonitorServerId() != null)
                    .collect(Collectors.groupingBy(InstanceInfo::getMonitorServerId));
            for (Map.Entry<Integer, List<InstanceInfo>> entry : serverId2InstanceListMap.entrySet()) {
                // 同步新增 参数包含httpTestId场景为数据源同步数据 不需要创建web场景
                if (entry.getValue().get(0).getData().get(CMDBTool.getFieldName(MwWebMonitorDto::getMw_httpTestId)) != null) {
                    continue;
                }
                createWebMonitor(entry.getKey(), entry.getValue(), true);
            }
        }
        if (CollectionUtils.isNotEmpty(webMonitorUpdateInstanceList)) {
            // 按照监控服务器分组调用
            Map<Integer, List<InstanceInfo>> serverId2InstanceListMap = webMonitorUpdateInstanceList.stream().filter(item -> item.getMonitorServerId() != null)
                    .collect(Collectors.groupingBy(InstanceInfo::getMonitorServerId));
            for (Map.Entry<Integer, List<InstanceInfo>> entry : serverId2InstanceListMap.entrySet()) {
                // 同步更新 参数包含agentInstanceName场景为数据源同步数据 不需要创建web场景
                if (entry.getValue().get(0).getData().get(CMDBTool.getFieldName(MwWebMonitorDto::getMw_agentInstanceName)) != null) {
                    continue;
                }
                // 先删除旧的web场景 再新增
                List<String> oldTestIds = entry.getValue().stream().map(item -> (String) item.getData().get(DatabaseUtils.getFieldName(MwWebMonitorDto::getMw_httpTestId))).filter(Objects::nonNull).toList();
                if (CollectionUtils.isNotEmpty(oldTestIds)) {
                    zabbixDubboService.getZabbixApiResult("httpTestDelete", entry.getKey(), oldTestIds);
                }
                createWebMonitor(entry.getKey(), entry.getValue(), false);
            }
        }
    }

    private void createWebMonitor(Integer monitorServerId, List<InstanceInfo> instanceInfoList, boolean isAdd) throws Exception {
        List<String> agentInstanceIds = instanceInfoList.stream().map(item -> (String) item.getData().get(DatabaseUtils.getFieldName(MwWebMonitorDto::getMw_agentInstanceId))).filter(Objects::nonNull).toList();
        List<InstanceInfo> agentInstanceInfos = this.selectListByIds(agentInstanceIds);
        Map<String, InstanceInfo> instanceId2InfoMap = agentInstanceInfos.stream().collect(Collectors.toMap(InstanceInfo::getId, item -> item));
        // 往zabbix中新增web监测服务
        MWZabbixAPIResult mwZabbixAPIResult = zabbixDubboService.getZabbixApiResult("httpTestBatchCreate", monitorServerId, parseWebMonitorParam(instanceInfoList, instanceId2InfoMap));
        if (mwZabbixAPIResult != null && mwZabbixAPIResult.isSuccess()) {
            JsonNode httpTestIds = ((ObjectNode) mwZabbixAPIResult.getData()).get("httptestids");
            List<String> newTestIds = new ArrayList<>();
            // 按照顺序设置新生成的httptestId
            for (int x = 0; x < httpTestIds.size(); x++) {
                String httpTestId = httpTestIds.get(x).asText();
                newTestIds.add(httpTestId);
                instanceInfoList.get(x).getData().put(CMDBTool.getFieldName(MwWebMonitorDto::getMw_httpTestId), httpTestId);
            }
            createWebMonitorTrigger(monitorServerId, instanceInfoList, instanceId2InfoMap, newTestIds);
        } else {
            log.error("add web monitor error! result:{}", JSON.toJSONString(mwZabbixAPIResult));
            throw new BusinessException(isAdd ? "web-monitor-add-error" : "web-monitor-update-error", instanceInfoList.stream().map(InstanceInfo::getInstanceName).toArray());
        }
    }

    private void createWebMonitorTrigger(Integer monitorServerId, List<InstanceInfo> instanceInfoList, Map<String, InstanceInfo> instanceId2InfoMap, List<String> newTestIds) {
        // zabbix创建web监测触发器
        List<MwModelWebMonitorTriggerParam> triggerParams = new ArrayList<>();
        MwWebMonitorDto mwWebMonitorDto;
        for (int i = 0; i < instanceInfoList.size(); i++) {
            mwWebMonitorDto = JSON.parseObject(JSON.toJSONString(instanceInfoList.get(i).getData()), MwWebMonitorDto.class);
            String webFailDescription = getWebDescription(instanceInfoList.get(i).getInstanceName(), WEB_TEST_RSPCODE);
            MwModelWebMonitorTriggerParam triggerFailCreateParam = new MwModelWebMonitorTriggerParam();
            triggerFailCreateParam.setDescription(webFailDescription);
            triggerFailCreateParam.setHostName(instanceId2InfoMap.get(mwWebMonitorDto.getMw_agentInstanceId()).getMonitorTypeName().replace(
                    instanceId2InfoMap.get(mwWebMonitorDto.getMw_agentInstanceId()).getInstanceName(), ""));
            triggerFailCreateParam.setWebName(instanceInfoList.get(i).getInstanceName());
            triggerFailCreateParam.setCode(String.valueOf(mwWebMonitorDto.getMw_statusCodes()));
            triggerFailCreateParam.setKey(WEB_TEST_RSPCODE);
            triggerFailCreateParam.setPriority(String.valueOf(TriggerAlarmLevelEnum.ERROR.getCode()));
            triggerParams.add(triggerFailCreateParam);

            MwModelWebMonitorTriggerParam triggerErrorCreateParam = new MwModelWebMonitorTriggerParam();
            triggerErrorCreateParam.setDescription(webFailDescription);
            triggerErrorCreateParam.setHostName(instanceId2InfoMap.get(mwWebMonitorDto.getMw_agentInstanceId()).getMonitorTypeName().replace(
                    instanceId2InfoMap.get(mwWebMonitorDto.getMw_agentInstanceId()).getInstanceName(), ""));
            triggerErrorCreateParam.setWebName(instanceInfoList.get(i).getInstanceName());
            triggerErrorCreateParam.setCode(String.valueOf(mwWebMonitorDto.getMw_statusCodes()));
            triggerErrorCreateParam.setKey(WEB_TEST_ERROR);
            triggerErrorCreateParam.setPriority(String.valueOf(TriggerAlarmLevelEnum.ERROR.getCode()));
            triggerParams.add(triggerErrorCreateParam);
        }
        MWZabbixAPIResult mwZabbixAPIResult = zabbixDubboService.getZabbixApiResult("triggerBatchCreate", monitorServerId, triggerParams);
        if (mwZabbixAPIResult == null || mwZabbixAPIResult.isFail()) {
            if (CollectionUtils.isNotEmpty(newTestIds)) {
                zabbixDubboService.getZabbixApiResult("httpTestDelete", monitorServerId, newTestIds);
            }
            throw new BusinessException("web-monitor-add-error", instanceInfoList.stream().map(InstanceInfo::getInstanceName).toArray());
        }
    }

    private String getWebDescription(String webName, String key) {
        StringBuffer sb = new StringBuffer("[网站监测]");
        sb.append("[" + webName + "]");
        if (key.equals(WEB_TEST_TIME)) {
            sb.append("网站延时持续6分钟大于200ms");
        } else if (key.equals(WEB_TEST_ERROR)) {
            sb.append("网页告警");
        } else {
            sb.append("网站状态故障");
        }
        return sb.toString();
    }

    private List<MWZabbixWebMonitorVo> parseWebMonitorParam(List<InstanceInfo> instanceInfoList, Map<String, InstanceInfo> instanceId2InfoMap) throws Exception {
        List<MWZabbixWebMonitorVo> paramList = new ArrayList<>();
        MWZabbixWebMonitorVo mwZabbixWebMonitorVo;
        MWZabbixWebStepVo mwZabbixWebStepVo;
        String agentInstanceId;
        String agentHostId;
        MwWebMonitorDto mwWebMonitorDto;
        for (int i = 0; i < instanceInfoList.size(); i++) {
            mwWebMonitorDto = JSON.parseObject(JSON.toJSONString(instanceInfoList.get(i).getData()), MwWebMonitorDto.class);
            mwZabbixWebMonitorVo = new MWZabbixWebMonitorVo();
            mwZabbixWebMonitorVo.setName(instanceInfoList.get(i).getInstanceName());
            mwZabbixWebMonitorVo.setAgent("Zabbix");
            // 设置调用服务器hostId
            agentInstanceId = mwWebMonitorDto.getMw_agentInstanceId();
            agentHostId = instanceId2InfoMap.get(agentInstanceId).getMonitorTypeId();
            mwZabbixWebMonitorVo.setHostid(agentHostId);
            mwZabbixWebMonitorVo.setDelay(mwWebMonitorDto.getMw_delay() + "s");
            mwZabbixWebMonitorVo.setStatus(mwWebMonitorDto.getMw_status() ? "0" : "1");
            mwZabbixWebMonitorVo.setHttp_proxy(mwWebMonitorDto.getMw_httpProxy());
            mwZabbixWebMonitorVo.setRetries(String.valueOf(mwWebMonitorDto.getMw_retries()));
            if (StringUtils.isNotEmpty(mwWebMonitorDto.getMw_httpTestId())) {
                mwZabbixWebMonitorVo.setHttptestid(mwWebMonitorDto.getMw_httpTestId());
            }

            mwZabbixWebStepVo = new MWZabbixWebStepVo();
            mwZabbixWebStepVo.setName(instanceInfoList.get(i).getInstanceName());
            mwZabbixWebStepVo.setNo("1");
            mwZabbixWebStepVo.setRequired(mwWebMonitorDto.getMw_required());
            mwZabbixWebStepVo.setStatus_codes(String.valueOf(mwWebMonitorDto.getMw_statusCodes()));
            mwZabbixWebStepVo.setUrl(mwWebMonitorDto.getMw_url());
            mwZabbixWebStepVo.setTimeout(mwWebMonitorDto.getMw_timeout() + "s");
            mwZabbixWebStepVo.setFollow_redirects(mwWebMonitorDto.getMw_followRedirects() ? "1" : "0");
            mwZabbixWebMonitorVo.setSteps(Arrays.asList(mwZabbixWebStepVo));
            paramList.add(mwZabbixWebMonitorVo);
        }
        return paramList;
    }

    /**
     * 实例新增参数转换
     *
     * @param param
     * @return
     */
    public List<String> instanceParamConvert(InstanceInfo param, ModelInfo modelInfo) {

        Map dataMap = param.getData();
        //获取资产实例的功能模块权限
        List<String> functionModule = new ArrayList<>();
        String functionModuleField = CMDBTool.getFieldName(ModelInfo::getFunctionModule);
        //数据组装
        if (dataMap != null) {
            // 使用Iterator和for循环来移除指定的键值对
            //权限字段不保存到data中，只保存在instanceInfo实体中
            Iterator<Map.Entry<String, Integer>> iterator = dataMap.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, Integer> entry = iterator.next();
                if (removeFieldDataList.contains(entry.getKey())) {
                    iterator.remove();
                }
            }
            if (dataMap.get(functionModuleField) != null) {
                functionModule = (List<String>) dataMap.get(functionModuleField);
            }
            List<String> path = new ArrayList<>();
            path.addAll(modelInfo.getGroupPath());
            path.add(param.getModelId());
            param.setPath(path);
            param.setGroupId(modelInfo.getGroupId());
            String status = strValueConvert(dataMap.get(prefix + CMDBTool.getFieldName(InstanceInfo::getStatus)));
            if (StringUtils.isNotEmpty(status)) {
                param.setStatus(status);
            }
            String type = strValueConvert(dataMap.get(prefix + CMDBTool.getFieldName(InstanceInfo::getTaskType)));
            if (StringUtils.isNotEmpty(type)) {
                param.setTaskType(type);
            }
        }
        //获取模板信息Id
        return functionModule;
    }

    /**
     * 配置业务系统外部关联对象Id路径
     */
    public void configRelationPath(InstanceInfo param) throws Exception {
        //组装业务系统外部关联的id路径
        MwCMDBConfigImpl configServer = (MwCMDBConfigImpl) cmdbServiceManage.getModelService(MwCMDBConfigImpl.ID);
        MwCMDBConfigInfo cmdbConfigInfo = configServer.doSelectByKey(relationParentModel.name());
        Object configValue = cmdbConfigInfo.getConfigValue();
        List<String> modelIds = new ArrayList<>();
        if (configValue instanceof List) {
            modelIds = (List<String>) configValue;
        }
        CustomModelServiceImpl modelServer = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
        ModelSearchParam searchParam = new ModelSearchParam();
        searchParam.setModelIds(modelIds);
        List<ModelInfo> ret = modelServer.doSelectList(searchParam);
        ModelInfo modelInfo = new ModelInfo();
        if (CollectionUtils.isNotEmpty(ret)) {
            modelInfo = ret.get(0);
        }
        if (modelInfo != null) {
            //获取本体属性
            List<PropertyInfo> currentModelPropertyInfo = modelInfo.getCurrentModelPropertyInfo();
            //按照属性顺序排序
            currentModelPropertyInfo.sort(Comparator.comparing(PropertyInfo::getSortNum, Comparator.nullsLast(Comparator.naturalOrder())));

            Map<String, Object> data = param.getData();
            List<String> path = new ArrayList<>();
            for (PropertyInfo propertyInfo : currentModelPropertyInfo) {
                //匹配出业务系统外部关联的数据
                if (data != null && data.containsKey(propertyInfo.getId())) {
                    Object o = data.get(propertyInfo.getId());
                    if (o instanceof Map) {
                        Map<String, String> relationMap = (Map<String, String>) o;
                        String relationId = "";
                        for (Map.Entry<String, String> entry : relationMap.entrySet()) {
                            log.info(entry.getKey() + ":::::" + entry.getValue());
                            if (relationIdKey.equals(entry.getKey())) {
                                relationId = entry.getValue();
                            }
                        }
                        path.add(relationId);
                    }
                }
            }
            if (CollectionUtils.isNotEmpty(path)) {
                String join = String.join(",", path);
                data.put(relationPath, join);
                param.setData(data);
            }
        }
    }

    public Object getFields(String modelId, String fieldViewAuthType) throws Exception {
        FieldViewAuthType type = FieldViewAuthType.valueOf(fieldViewAuthType);
        return getFields(modelId, type);
    }

    public Object getFields(String modelId, FieldViewAuthType fieldViewAuthType) throws Exception {
        ModelInfo modelInfo = getModelInfo(modelId);
        List ret = getAuthPropertyInfo(modelInfo.getPropertyInfoList(), fieldViewAuthType);
        return ret;
    }

    private List<PropertyInfo> getAuthPropertyInfo(List<PropertyInfo> propertyInfos, FieldViewAuthType fieldViewAuthType) {
        List ret = new ArrayList();
        for (PropertyInfo propertyInfo : propertyInfos) {
            Set<FieldViewAuthType> fieldViewAuthTypes = propertyInfo.getFieldViewAuthTypes();
            if (null != fieldViewAuthTypes && fieldViewAuthTypes.contains(fieldViewAuthType)) {
                ret.add(propertyInfo);
            }
        }
        return ret;
    }

    public long countInstanceInfoByModelId(String modelId) throws Exception {
        String modelIdKey = CMDBTool.getFieldName(InstanceInfo::getModelId);
        Query query = new Query(Criteria.where(modelIdKey).is(modelId));
        query.addCriteria(CriteriaWrapper.where(InstanceInfo::getDelFlag).is(false));
        long count = instanceInfoMapper.count(query);
        return count;
    }

    public Map countInstanceInfoGroupByModelId(List<String> modelIds) {
        if (null == modelIds || modelIds.size() == 0) {
            return null;
        }
        String modelIdKey = CMDBTool.getFieldName(InstanceInfo::getModelId);
        Criteria criteria = Criteria.where(modelIdKey).in(modelIds);
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(criteria)
                , Aggregation.group(modelIdKey).count().as("count")
                , Aggregation.sort(Sort.Direction.DESC, "count")
        );
        AggregationResults<Map> result = instanceInfoMapper.aggregate(aggregation, InstanceInfo.class, Map.class);
        Map<String, Object> mergedResultMap = new HashMap<>(); // 遍历每个Map对象并将其合并到mergedResultMap中
        for (Map<String, Object> map : result) {
            mergedResultMap.put(strValueConvert(map.get(KEY_ID)), longValueConvert(map.get(COUNT)));
        }
        return mergedResultMap;
    }

    public void init() {
        resetPrefixFields = new HashSet<>();
        CMDBTool.visitCMDBAnnotion(InstanceInfoExtend.class, new Consumer<PropDesc>() {
            @Override
            public void accept(PropDesc propDesc) {
                resetPrefixFields.add(propDesc.getFieldName());
            }
        });
    }

    /**
     * 获取模型实例功能模块
     *
     * @param modelId
     * @return
     */
    public List<MwModelLabelValueParam> getFunctionModule(String modelId) throws Exception {
        CustomModelServiceImpl service = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
        List<String> fields = new ArrayList<>();
        fields.add(CMDBTool.getFieldName(ModelInfo::getFunctionModule));
        List<ModelInfo> modelInfos = service.getModelInfoByIncludesField(Arrays.asList(modelId), fields);
        List<MwModelLabelValueParam> functionModule = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(modelInfos) && modelInfos.get(0) != null) {
            ModelInfo modelInfo = modelInfos.get(0);
            functionModule = modelInfo.getFunctionModuleList();
        }
        return functionModule;
    }

    /**
     * 获取实例详情页面tab信息
     *
     * @param instanceId 实例id
     * @return
     */
    public List<String> getInstanceDetailTabInfo(String instanceId) {
        List<String> list = new ArrayList<>();
        InstanceInfo instanceInfo = new InstanceInfo();
        instanceInfo.setId(instanceId);
        InstanceInfo info = doSelectById(instanceInfo);


        return list;
    }

    /**
     * 批量删除监控服务器资产
     *
     * @param instanceInfoList
     */
    public void batchDelMonitorAssets(List instanceInfoList) throws Exception {
        if (CollectionUtils.isNotEmpty(instanceInfoList)) {
            MwInstanceMonitorManage monitorManage = new MwInstanceMonitorManage(zabbixDubboService);
            List<QueryMonitorValue> zabbixParams = monitorManage.zabbixParamListConvert(instanceInfoList);
            monitorManage.handlerMonitorMethodThread(zabbixParams, null, batchDelMonitorAssets.getName());
        }
    }

    /**
     * 获取资产监控状态
     *
     * @param instanceInfo
     */
    public void getAssetsStatusByOne(InstanceInfo instanceInfo) throws Exception {
        String monitorTypeId = instanceInfo.getMonitorTypeId();
        Integer monitorServerId = instanceInfo.getMonitorServerId();
        if ((!Strings.isNullOrEmpty(monitorTypeId) && !"0".equals(monitorTypeId)) && (monitorServerId != null && monitorServerId.intValue() != 0)) {
            MwInstanceMonitorManage monitorManage = new MwInstanceMonitorManage(zabbixDubboService);
            List<QueryMonitorValue> zabbixParams = monitorManage.zabbixParamListConvert(Arrays.asList(instanceInfo));
            QueryMonitorValue queryMonitorValue = new QueryMonitorParam();
            if (CollectionUtils.isNotEmpty(zabbixParams)) {
                queryMonitorValue = zabbixParams.get(0);
            }
            MwTPServerTable mwTPServerTable = new MwTPServerTable();
            mwTPServerTable.setMonitoringServerType(queryMonitorValue.getMonitorType());
            MonitorProcessor processor = MonitorProcessor.build(mwTPServerTable, null);
            MonitorParamContext context = MonitorParamContext.build();
            context.setZabbixDubboService(zabbixDubboService);
            context.setQueryMonitorParam(queryMonitorValue);
            List assetsStatus = processor.getInstanceMonitorState(context);
            //调用获取资产状态方法
            Map<String, String> statusMap = new HashMap<>();
            //item返回数据处理
            itemResultStatusConvert(assetsStatus, statusMap);
            //资产状态信息处理
            instanceStatusConvert(Arrays.asList(instanceInfo), statusMap);
        }
    }


    /**
     * 获取资产监控状态
     *
     * @param instanceInfoList
     */
    public void getAssetsStatus(List instanceInfoList) throws Exception {
        if (CollectionUtils.isNotEmpty(instanceInfoList)) {
            MwInstanceMonitorManage monitorManage = new MwInstanceMonitorManage(zabbixDubboService);
            List<QueryMonitorValue> zabbixParams = monitorManage.zabbixParamListConvert(instanceInfoList);
            //调用获取资产状态方法
            List<Object> assetsStatus = monitorManage.handlerMonitorMethodThread(zabbixParams, null, getInstanceMonitorState.getName());
            Map<String, String> statusMap = new HashMap<>();
            //item返回数据处理
            itemResultStatusConvert(assetsStatus, statusMap);
            //资产状态信息处理
            instanceStatusConvert(instanceInfoList, statusMap);
        }

    }

    /**
     * 资产状态信息处理
     *
     * @param instanceInfoList
     * @param instanceStateMap
     */
    private void instanceStatusConvert(List instanceInfoList, Map<String, String> instanceStateMap) {
        if (CollectionUtils.isNotEmpty(instanceInfoList)) {
            for (Object instanceInfos : instanceInfoList) {
                InstanceInfo instanceInfo = (InstanceInfo) instanceInfos;
                //如果资产状态为告警，则不更新
                if(!Strings.isNullOrEmpty(instanceInfo.getItemAssetsStatus()) && ALERT.getName().equals(instanceInfo.getItemAssetsStatus()) ){
                    continue;
                }
                String key = instanceInfo.getMonitorServerId() + "_" + instanceInfo.getMonitorTypeId();
                if (instanceStateMap != null && instanceStateMap.containsKey(key)) {
                    instanceInfo.setItemAssetsStatus(instanceStateMap.get(key));
                } else {
                    instanceInfo.setItemAssetsStatus(UNKNOWN.getName());
                }
            }
        }
    }

    /**
     * item返回数据处理
     *
     * @param assetsStatus
     * @param statusMap
     */
    public void itemResultStatusConvert(List assetsStatus, Map<String, String> statusMap) {
        List<String> itemNames = ZabbixItemConstant.NEW_ASSETS_STATUS;
        Set<String> hostSets = new HashSet();
        List<MwZabbixItemResultParam> list = new ArrayList<>();
        for (Object item : assetsStatus) {
            if (item instanceof List) {
                list.addAll((List<MwZabbixItemResultParam>) item);
            } else {
                MwZabbixItemResultParam item1 = (MwZabbixItemResultParam) item;
                list.add(item1);
            }
        }
        for (MwZabbixItemResultParam node : list) {
            int serverId = node.getMonitorServerId();
            if (itemNames.contains(node.getName())) {
                if (ZabbixItemEnum.MW_DB_STATUS.getItemName().equals(node.getName())) {
                    String status = ZabbixAssetsStatusEnum.getAssetsStatusName(intValueConvert(node.getLastvalue()));
                    statusMap.put(serverId + "_" + node.getHostid(), status);
                    hostSets.add(node.getHostid());
                }
                if (hostSets.contains(node.getHostid())) {
                    continue;
                }
                if (ZabbixItemEnum.MW_HOST_AVAILABLE.getItemName().equals(node.getName())) {
                    String status = ZabbixAssetsStatusEnum.getAssetsStatusName(intValueConvert(node.getLastvalue()));
                    statusMap.put(serverId + "_" + node.getHostid(), status);
                    hostSets.add(node.getHostid());
                }
                if (hostSets.contains(node.getHostid())) {
                    continue;
                }
                String status = ZabbixAssetsStatusEnum.getAssetsStatusName(intValueConvert(node.getLastvalue()));
                statusMap.put(serverId + "_" + node.getHostid(), status);
                continue;
            }
            statusMap.put(serverId + "_" + node.getHostid(), ZabbixAssetsStatusEnum.SHUTDOWN.getStatus());
        }

    }


    /**
     * 资产实例批量修改同步处理
     */
    private void batchEditorSyncHandle(BatchEditorViewInstance param) throws Exception {
      if(param != null && !booleanValueConvert(param.getTimeTaskFlag())) {
          //修改监控状态
          batchEditorMonitorStatus(param);
          //批量修改接口监控信息
          batchEditorInterfaceMonitorInfos(param);
      }
    }


    /**
     * 修改监控状态
     *
     * @param param
     */
    private void batchEditorMonitorStatus(BatchEditorViewInstance param) throws Exception {
        if (CollectionUtils.isNotEmpty(param.getInstanceIds()) && param.getMw_monitorFlag()!=null) {
            InstanceSearchParam instanceSearchParam = new InstanceSearchParam();
            instanceSearchParam.setInstanceIds(param.getInstanceIds());
            List<InstanceInfo> instanceInfoList = selectListByIds(instanceSearchParam);
            if (CollectionUtils.isNotEmpty(instanceInfoList)) {
                MwInstanceMonitorManage monitorManage = new MwInstanceMonitorManage(zabbixDubboService);
                List<QueryMonitorValue> zabbixParams = monitorManage.zabbixParamListConvert(instanceInfoList);

                if (CollectionUtils.isNotEmpty(instanceInfoList)) {
                    //根据MonitorType区分，过滤保留serverId，hostId有值的实例数据
                    List<InstanceInfo> disList = instanceInfoList.stream().filter(s -> !Strings.isNullOrEmpty(s.getMonitorType())
                            && intValueConvert(s.getMonitorServerId()) != 0
                            && !Strings.isNullOrEmpty(s.getMonitorTypeId())).collect(Collectors.toList());
                    instanceInfoList.removeAll(disList);
                    List<String> collect = instanceInfoList.stream().filter(s -> !Strings.isNullOrEmpty(s.getInstanceName())).map(s -> s.getInstanceName()).collect(Collectors.toList());
                    if (CollectionUtils.isNotEmpty(collect)) {
                        throw new BatchUpdateMonitorStatusException(String.join(",", collect));
                    }
                }
                List<MwInstanceZabbixParam> params = new ArrayList<>();
                //批量编辑时，参数处理(BatchEditorViewInstance要修改的字段和mwInstanceZabbixParam保持一致:mw_monitorFlag、)
//                for (QueryMonitorValue queryMonitorValue : zabbixParams) {
//                    MwInstanceZabbixParam zabbixParam =  JSONObject.parseObject(JSONObject.toJSONString(queryMonitorValue) ,MwInstanceZabbixParam.class);
//                    if (param != null) {
//                        BeanUtil.copyProperties(param, zabbixParam, CopyOptions.create().setIgnoreNullValue(true));
//                    }
//                    params.add(zabbixParam);
//                }
                //调用修改主机监控转态方法
                monitorManage.handlerMonitorMethodThread(zabbixParams, param, updateHostState.getName());
            }
        }
    }

    /**
     * 批量修改接口Trunk监控信息
     *
     * @param param
     */
    private void batchEditorInterfaceMonitorInfos(BatchEditorViewInstance param) throws Exception {
        if (CollectionUtils.isNotEmpty(param.getInstanceIds()) && param.getMw_trunkMonitorFlag()!=null) {
            log.info("批量修改接口Trunk监控信息"+param);
            AssetsManageServiceImpl bean = SpringUtils.getBean(AssetsManageServiceImpl.class);
            bean.batchEditorInterfaceMonitor(param.getInstanceIds(),param.getMw_trunkMonitorFlag());
        }
    }


    private Pair<Query, Update> convertUpdateByInstance(InstanceInfo instanceInfo) throws Exception {
        return convertUpdateByInstanceInfo(instanceInfo, false);
    }

    private Pair<Query, Update> convertUpdateByInstance(InstanceInfo instanceInfo, boolean ignoreNull) throws Exception {
        return convertUpdateByInstanceInfo(instanceInfo, ignoreNull);
    }

    private Pair<Query, Update> convertUpdateByInstanceInfo(InstanceInfo instanceInfo, boolean ignoreNull) throws Exception {
        Map<String, PropertyInfo> propertyInfoById = new HashMap<>();
        String modelId = instanceInfo.getModelId();
        if (!Strings.isNullOrEmpty(modelId)) {
            ModelInfo modelInfo = getModelInfo(modelId);
            propertyInfoById = modelInfo.getPropertyInfoById();
        }
        Query query = new Query(CriteriaWrapper.where(InstanceInfo::getId).is(instanceInfo.getId()));
        log.info("convertUpdateByInstance::" + instanceInfo);
        //根据map字段产生更新信息
        Update update = new Update();
        update = CMDBTool.genMongoUpdate(instanceInfo.getData(), InstanceInfo.SearchPrefix, null, propertyInfoById, ignoreNull);
        //根据类注解信息产生更新信息
        update = CMDBTool.genMongoUpdate(instanceInfo, null, update);
        Pair<Query, Update> updatePair = Pair.of(query, update);
        return updatePair;
    }


    public boolean batchUpdateByInstanceMap(List<Map> maps) throws Exception {
        List<Pair<Query, Update>> updateList = new ArrayList<>();
        BulkOperations operations = instanceInfoMapper.bulkOps(BulkOperations.BulkMode.UNORDERED, InstanceInfo.class);
        for (Map ms : maps) {
            Query query = new Query();
            String id = strValueConvert(ms.get(idKey));
            query.addCriteria(CriteriaWrapper.where(InstanceInfo::getId).is(id));
            Update update = genMongoUpdateByMap(ms, new Update(),Arrays.asList(idKey));
            Pair<Query, Update> updatePair = Pair.of(query, update);
            updateList.add(updatePair);
        }
        operations.updateMulti(updateList);
        operations.execute();
        return true;
    }


    /**
     * 获取操作日志模型信息
     *
     * @param list 变更历史信息
     */
    public List<InstanceChangeHisVO> getOperatorLogModelInfo(List<InstanceChangeHisVO> list, AssetsOperatorHisSearchParam param) throws Exception {
        if (CollectionUtils.isEmpty(list)) {
            return List.of();
        }
        List<String> modelIdList = list.stream().map(InstanceChangeHisVO::getModelId).filter(StrUtil::isNotBlank).distinct().toList();
        if (CollectionUtils.isEmpty(modelIdList)) {
            return List.of();
        }
        List<String> fieldList = null;
        if (null != param && CollUtil.isNotEmpty(param.getFieldList())) {
            fieldList = param.getFieldList();
        }

        long start1 = System.currentTimeMillis();
        ChangeRecordConversionDTO dto = changeRecordConversionDTO(modelIdList);
        long end1 = System.currentTimeMillis();
        log.info("查库耗时：{}ms", end1 - start1);
        Set<Long> orgIds = new HashSet<>();
        Set<Long> userIdList = new HashSet<>();
        Set<Long> groupIdList = new HashSet<>();
        for (InstanceChangeHisVO vo : list) {
            Map<String, Map<String, ModelPropertyParam>> modelPropertyGroupMap = dto.getModelPropertyGroupMap();
            Map<String, ModelPropertyParam> modelPropertyMap = modelPropertyGroupMap.get(vo.getModelId());
            getQueryIdList(vo.getOperateDesBefore(), modelPropertyMap, orgIds, userIdList, groupIdList);
            getQueryIdList(vo.getOperateDesAfter(), modelPropertyMap, orgIds, userIdList, groupIdList);
        }

        List<MwUser> usersByUserIds = userApi.getUsersByUserIds(new ArrayList<>(userIdList));
        List<OrgDTO> orgListByOrgIds = userApi.getOrgListByOrgIds(new ArrayList<>(orgIds));
        List<GroupDTO> groupListByIds = userApi.getGroupListByIds(new ArrayList<>(groupIdList));
        if (CollUtil.isNotEmpty(usersByUserIds)) {
            Map<Long, MwUser> usermap = usersByUserIds.stream().collect(Collectors.toMap(MwUser::getId, Function.identity(), (k1, k2) -> k1));
            dto.setUserMap(usermap);
        }
        if (CollUtil.isNotEmpty(orgListByOrgIds)) {
            Map<Long, OrgDTO> orgMap = orgListByOrgIds.stream().collect(Collectors.toMap(OrgDTO::getId, Function.identity(), (k1, k2) -> k1));
            dto.setOrgMap(orgMap);
        }
        if (CollUtil.isNotEmpty(groupListByIds)) {
            Map<Long, GroupDTO> groupMap = groupListByIds.stream().collect(Collectors.toMap(GroupDTO::getId, Function.identity(), (k1, k2) -> k1));
            dto.setGroupMap(groupMap);
        }
        Map<String, String> modelInfoMap = Optional.ofNullable(dto.getModelInfoMap()).orElse(new HashMap<>());
        List<InstanceChangeHisVO> retList = new ArrayList<>();
        for (InstanceChangeHisVO vo : list) {
            String modelId = vo.getModelId();
            vo.setMwModelName(modelInfoMap.getOrDefault(modelId, ""));
            // 保存的操作实例json 字符串转为 JSON NODE
            if (vo.getType().equalsIgnoreCase(OperatorTypeDescEnum.remove.getCname()) ||
                    vo.getType().equalsIgnoreCase(OperatorTypeDescEnum.batchRemove.getCname())) {
                vo.setOperateDesAfter("");
            }
            JsonNode jsonAfterNode = convertFieldsToDescriptions(vo.getOperateDesAfter(), dto, modelId);
            JsonNode jsonBeforeNode = convertFieldsToDescriptions(vo.getOperateDesBefore(), dto, modelId);

            Map<String, ModelPropertyParam> propertyMap = dto.getModelPropertyGroupMap().get(modelId);

            JsonComparatorUtil.DiffResult diffResult;
            // 获取字段差异化
            if (CollectionUtils.isNotEmpty(fieldList)) {
                diffResult = JsonComparatorUtil.generateHtmlWithHighlights(jsonBeforeNode, jsonAfterNode, fieldList, propertyMap);
                if (ObjUtil.isEmpty(diffResult)) {
                    continue;
                }
            } else {
                diffResult = JsonComparatorUtil.generateHtmlWithHighlights(jsonBeforeNode, jsonAfterNode);
            }
            if (diffResult != null) {
                String changeSummary = StrUtil.isNotBlank(diffResult.getChangeSummary()) ? diffResult.getChangeSummary() : SUMMARY_EMPTY;
                vo.setChangeSummary(changeSummary);
                vo.setOperateDesAfter(mapStructureFormat(diffResult.getAfter()));
                vo.setOperateDesBefore(mapStructureFormat(diffResult.getBefore()));
            }
            retList.add(vo);

        }
        if (null != param && StrUtil.isNotBlank(param.getSortOrder())) {
            boolean isAsc = ascSortModel.equals(param.getSortOrder());
            //列表字段排序
            sortListByField(retList, param.getSortName(), isAsc);
        }
        return retList;
    }

    private void getQueryIdList(String vo, Map<String, ModelPropertyParam> modelPropertyMap,
                                Set<Long> orgIds, Set<Long> userIdList, Set<Long> groupIdList) {
        if (StrUtil.isBlank(vo)) {
            return;
        }
        Map<String, Object> beforeInstanceMap = JSONUtil.toBean(vo, Map.class);

        getUserOrOrgOrGroupId(modelPropertyMap, orgIds, userIdList, groupIdList, beforeInstanceMap);

    }

    private void getUserOrOrgOrGroupId(Map<String, ModelPropertyParam> modelPropertyMap, Set<Long> orgIds, Set<Long> userIdList,
                                       Set<Long> groupIdList, Map<String, Object> beforeInstanceMap) {
        for (Map.Entry<String, Object> entry : beforeInstanceMap.entrySet()) {
            try {
                String fieldName = entry.getKey();
                if (modelPropertyMap.containsKey(fieldName)) {
                    Object value = entry.getValue();
                    ModelPropertyParam fieldProperty = modelPropertyMap.get(fieldName);
                    PropertyTypeRef propertyTypeRef = fieldProperty.getPropertyTypeRef();
                    getUserOrGroupOrOrgIds(value, propertyTypeRef, orgIds, userIdList, groupIdList);
                }
                if (CMDBTool.getFieldName(DataAuth::getOrgIds).equals(fieldName)) {
                    JSONArray jsonArray = JSONArray.parseArray(entry.getValue().toString());
                    if (CollUtil.isNotEmpty(jsonArray)) {
                        List<Long> ids = CMDBTool.parseStringToList(entry.getValue().toString());
                        orgIds.addAll(ids);
                    }
                }
                if (CMDBTool.getFieldName(InstanceInfo::getData).equals(fieldName)) {
                    Map<String, Object> dataValue = (Map<String, Object>) entry.getValue();
                    getUserOrOrgOrGroupId(modelPropertyMap, orgIds, userIdList, groupIdList, dataValue);
                }
            } catch (Exception e) {
                log.error("get user info failed: {}", e.getMessage());
            }
        }
    }

    private ChangeRecordConversionDTO changeRecordConversionDTO(List<String> modelIdList) throws Exception {
        CustomModelServiceImpl customModelService = (CustomModelServiceImpl) cmdbServiceManage.getModelService(CustomModelServiceImpl.ID);
        ModelSearchParam modelSearchParam = new ModelSearchParam();
        modelSearchParam.setModelIds(modelIdList);
        List<ModelInfo> modelInfos = Optional.ofNullable(customModelService.doSelectList(modelSearchParam)).orElse(new ArrayList<>());
        Map<String, String> modelInfoMap = new HashMap<>(modelInfos.size());
        for (ModelInfo info : modelInfos) {
            if (StrUtil.isBlank(info.getId())) {
                continue;
            }
            modelInfoMap.put(info.getId(), info.getModelName());
        }

        ModelVendorServiceImpl vendorService = (ModelVendorServiceImpl) cmdbServiceManage.getModelService(ModelVendorServiceImpl.ID);
        List<ModelVendorInfo> modelVendorInfos = Optional.ofNullable(vendorService.doSelectList(new VendorSearchParam())).orElse(new ArrayList<>());
        Map<String, String> vendorInfoMap = new HashMap<>(modelVendorInfos.size());
        for (ModelVendorInfo info : modelVendorInfos) {
            if (StrUtil.isBlank(info.getId())) {
                continue;
            }
            vendorInfoMap.put(info.getId(), info.getVendorCN());
        }

        ModelSpecificationServiceImpl specificationService = (ModelSpecificationServiceImpl) cmdbServiceManage.getModelService(ModelSpecificationServiceImpl.ID);
        List<ModelSpecificationInfo> specificationInfoList = Optional.ofNullable(specificationService.doSelectList(new SpecificationSearchParam())).orElse(new ArrayList<>());
        Map<String, String> specificationInfoMap = new HashMap<>(specificationInfoList.size());
        for (ModelSpecificationInfo info : specificationInfoList) {
            if (StrUtil.isBlank(info.getId())) {
                continue;
            }
            vendorInfoMap.put(info.getId(), info.getSpecification());
        }

        ModelPropertyServiceImpl service = (ModelPropertyServiceImpl) cmdbServiceManage.getModelService(ModelPropertyServiceImpl.ID);

        Map<String, Map<String, ModelPropertyParam>> modelPropertyGroupMap = new HashMap<>();
        for (String modelId : modelIdList) {
            PropertySearchParam param = new PropertySearchParam();
            // 暂时用单个，整体逻辑写完跟完批量
            param.setModelId(modelId);
            param.setInputType(FieldViewAuthType.add.name());
            List<ModelPropertyParam> propertyList = Optional.ofNullable(service.listInputProperty(param)).orElse(new ArrayList<>());
            Map<String, ModelPropertyParam> modelPropertyMap = new HashMap<>(propertyList.size());
            for (ModelPropertyParam info : propertyList) {
                if (StrUtil.isBlank(info.getId())) {
                    continue;
                }
                modelPropertyMap.put(info.getId(), info);
            }

            modelPropertyGroupMap.put(modelId, modelPropertyMap);
        }

        ModelTemplateServiceImpl templateService = (ModelTemplateServiceImpl) cmdbServiceManage.getModelService(ModelTemplateServiceImpl.ID);
        List<ModelTemplateInfo> templateInfoList = Optional.ofNullable(templateService.doSelectList(new TemplateSearchParam())).orElse(new ArrayList<>());
        Map<String, String> templateInfoMap = new HashMap<>(templateInfoList.size());
        for (ModelTemplateInfo info : templateInfoList) {
            if (StrUtil.isBlank(info.getId())) {
                continue;
            }
            templateInfoMap.put(info.getId(), info.getTemplateName());
        }
        return ChangeRecordConversionDTO
                .builder()
                .modelInfoMap(modelInfoMap)
                .modelPropertyGroupMap(modelPropertyGroupMap)
                .vendorInfoMap(vendorInfoMap)
                .specificationInfoMap(specificationInfoMap)
                .templateInfoMap(templateInfoMap)
                .build();
    }

    // 将字段名转为description的值，并返回一个字段串
    public JsonNode convertFieldsToDescriptions(String operateDer, ChangeRecordConversionDTO dto, String modelId) throws JsonProcessingException {
        if (StrUtil.isBlank(operateDer)) {
            return mapper.readTree(StrUtil.EMPTY_JSON);
        }
        Map<String, Object> retMap = new LinkedHashMap<>();


        Map<String, Map<String, ModelPropertyParam>> modelPropertyGroupMap = dto.getModelPropertyGroupMap();
        Map<String, ModelPropertyParam> modelPropertyMap = modelPropertyGroupMap.get(modelId);
        Map<String, Object> instanceMap = JSONUtil.toBean(operateDer, Map.class);
        String instanceId = (String) instanceMap.get(CMDBTool.getFieldName(InstanceInfo::getId));

        // 外层字段转换
        for (Map.Entry<String, Object> entry : instanceMap.entrySet()) {
            String fieldName = entry.getKey();
            if (modelPropertyMap.containsKey(fieldName)) {
                Object value = entry.getValue();
                ModelPropertyParam fieldProperty = modelPropertyMap.get(fieldName);
                String fieldNameDesc = fieldProperty.getName();
                String valueDesc = getValueDescByInfo(value, dto);
                String v = specialFieldConvert(fieldName, value, fieldProperty, dto, instanceId);
                if (StrUtil.isNotBlank(fieldNameDesc)) {
                    if (StrUtil.isBlank(valueDesc)) {
                        valueDesc = entry.getValue().toString();
                    }
                    if (StrUtil.isNotBlank(v)) {
                        valueDesc = v;
                    }
                    retMap.put(fieldNameDesc, valueDesc);
                }
            }
        }
        // data对象内部转换
        Object instanceDataMap = instanceMap.get(CMDBTool.getFieldName(InstanceInfo::getData));
        if (ObjUtil.isNotEmpty(instanceDataMap)) {
            Map<String, Object> dataMap = (Map<String, Object>) instanceDataMap;
            for (Map.Entry<String, Object> entry : dataMap.entrySet()) {
                try {
                    ModelPropertyParam propertyParam = modelPropertyMap.get(entry.getKey());
                    if (ObjUtil.isEmpty(propertyParam)) {
                        continue;
                    }
                    String fieldNameDesc = propertyParam.getName();
                    String valueDesc = getValueDescByInfo(entry.getValue(), dto);
                    String v = specialFieldConvert(entry.getKey(), entry.getValue(), propertyParam, dto, instanceId);
                    if (StrUtil.isNotBlank(fieldNameDesc)) {
                        if (StrUtil.isBlank(valueDesc)) {
                            valueDesc = entry.getValue().toString();
                        }
                        if (StrUtil.isNotBlank(v)) {
                            valueDesc = v;
                        }
                        retMap.put(fieldNameDesc, valueDesc);
                    }
                } catch (Exception e) {
                    log.error("source data json: {}.\n field: {}.\n value: {}", JSONUtil.toJsonStr(dataMap), entry.getKey(), entry.getValue().toString());
                    log.error("Field convert failed ", e);
                }
            }
        }
        String resultStr = "";
        if (MapUtil.isNotEmpty(retMap)) {
            resultStr = JSON.toJSONString(retMap);
        }

        return mapper.readTree(resultStr);
    }

    private String specialFieldConvert(String fieldName, Object value, ModelPropertyParam property, ChangeRecordConversionDTO dto, String instanceId) {
        // MwRelationInstanceParam
        // modelClassify,modelSystem
        if (value == null || StrUtil.isBlank(value.toString()) || value.toString().equals("[]")) {
            return StrUtil.EMPTY;
        }
        String[] specialFields = {CMDBTool.getFieldName(BaseModelInfo::getModelClassify), CMDBTool.getFieldName(BaseModelInfo::getModelSystem)};
        if (Arrays.stream(specialFields).toList().contains(fieldName) && StrUtil.isNotBlank(value.toString())) {
            MwRelationInstanceParam bean = JSONUtil.toBean(value.toString(), MwRelationInstanceParam.class);
            return bean.getRelationName();
        }
        PropertyTypeRef propertyTypeRef = property.getPropertyTypeRef();
        StringBuilder sb = new StringBuilder();
        if (PropertyTypeOrg.ID.equals(propertyTypeRef.getTypeId())) {
            // 机构时二位数组
            Map<Long, OrgDTO> orgMap = Optional.ofNullable(dto.getOrgMap()).orElse(new HashMap<>());
            List<List<Long>> lists = CMDBTool.stringToListList(value.toString());
            for (List<Long> ids : lists) {
                Long orgId = ids.get(ids.size() - 1);
                if (orgMap.get(orgId) != null) {
                    sb.append(orgMap.get(orgId).getOrgName()).append(",");
                }
            }

        } else if (PropertyTypeGroup.ID.equals(propertyTypeRef.getTypeId())) {
            Map<Long, GroupDTO> groupMap = Optional.ofNullable(dto.getGroupMap()).orElse(new HashMap<>());
            // 组和是数组
            List<Long> longs = CMDBTool.parseStringToList(value.toString());
            for (Long gId : longs) {
                GroupDTO groupDTO = groupMap.get(gId);
                if (ObjUtil.isNotNull(groupDTO)) {
                    sb.append(groupDTO.getGroupName()).append(",");
                }
            }

        } else if (PropertyTypeUser.ID.equals(propertyTypeRef.getTypeId())) {
            // 用户是数组
            Map<Long, MwUser> userMap = Optional.ofNullable(dto.getUserMap()).orElse(new HashMap<>());
            // 组和是数组
            List<Long> longs = CMDBTool.parseStringToList(value.toString());
            for (Long uId : longs) {
                MwUser userDto = userMap.get(uId);
                if (ObjUtil.isNotNull(userDto)) {
                    sb.append(userDto.getNickName()).append(",");
                }
            }
        } else if (PropertyTypeDate.ID.equals(propertyTypeRef.getTypeId())) {
            return new SimpleDateFormat(DateConstant.NORM_DATETIME).format(value);
        } else if (PropertyTypeExtSingle.ID.equals(propertyTypeRef.getTypeId()) || PropertyTypeExtMultiple.ID.equals(propertyTypeRef.getTypeId())) {
            MwRelationPropertyType propertyType = PropertyTypeManage.getInterfacePropertyType(propertyTypeRef.getTypeId());
            Object relationName = propertyType.getRelationName(fieldName, value, instanceId);
            return relationName.toString();
        }
        if (StrUtil.isNotBlank(sb.toString())) {
            return sb.deleteCharAt(sb.length() - 1).toString();
        }
        return StrUtil.EMPTY;
    }


    private void getUserOrGroupOrOrgIds(Object value, PropertyTypeRef propertyTypeRef,
                                        Set<Long> orgIdList, Set<Long> userIdList, Set<Long> groupIdList) {
        if (PropertyTypeOrg.ID.equals(propertyTypeRef.getTypeId())) {
            // 机构时二位数组
            List<List<Long>> orgIds = CMDBTool.stringToListList(value.toString());
            for (List<Long> ids : orgIds) {
                Long orgId = ids.get(ids.size() - 1);
                orgIdList.add(orgId);
            }
        } else if (PropertyTypeGroup.ID.equals(propertyTypeRef.getTypeId())) {
            JSONArray jsonArray = JSONArray.parseArray(value.toString());
            if (CollUtil.isNotEmpty(jsonArray)) {
                // 组和是数组
                List<Long> ids = CMDBTool.parseStringToList(value.toString());
                groupIdList.addAll(ids);
            }
        } else if (PropertyTypeUser.ID.equals(propertyTypeRef.getTypeId())) {
            JSONArray jsonArray = JSONArray.parseArray(value.toString());
            if (CollUtil.isNotEmpty(jsonArray)) {
                // 用户是数组
                List<Long> ids = CMDBTool.parseStringToList(value.toString());
                userIdList.addAll(ids);
            }
        }
    }


    private String getValueDescByInfo(Object value, ChangeRecordConversionDTO dto) {
        Map<String, String> modelInfoMap = dto.getModelInfoMap();

        String valueStr = value.toString();
        if (modelInfoMap.get(valueStr) != null) {
            return modelInfoMap.get(valueStr);
        }
        if (dto.getVendorInfoMap().get(valueStr) != null) {
            return dto.getVendorInfoMap().get(valueStr);
        }
        if (dto.getSpecificationInfoMap().get(valueStr) != null) {
            return dto.getSpecificationInfoMap().get(valueStr);
        }
        if (dto.getTemplateInfoMap().get(valueStr) != null) {
            return dto.getTemplateInfoMap().get(valueStr);
        }

        return StrUtil.EMPTY;
    }

    private String mapStructureFormat(String jsonStr) {
        if (StrUtil.isNotBlank(jsonStr)) {
            if (!JSONUtil.isTypeJSON(jsonStr)) {
                return jsonStr;
            }
            Map map = JSON.parseObject(jsonStr, Map.class);
            StringBuilder sb = new StringBuilder();
            for (Object obj : map.entrySet()) {
                sb.append(obj).append("<br/>");
            }
            return sb.toString().replaceAll("(?i)<br/>(<br/>+)", "<br/>");
        }
        return "";
    }

    public List<InstanceInfo> batchAddInstanceParamConvert(Object params) throws Exception {
        List<InstanceInfo> instanceInfoList = new ArrayList<>();
        if (params instanceof BatchAddAndUpdInstanceParam) {
            List paramList = ((BatchAddAndUpdInstanceParam) params).getParams();
            if (null != paramList) {
                Object data = paramList.get(0);
                if (data instanceof Map) {
                    for (Object item : paramList) {
                        Map m = (Map) item;
                        ModelService modelService = cmdbServiceManage.getModelService(ID);
                        Object convert = cmdbServiceManage.convert(modelService, m);
                        //将map参数转为InstanceInfo
                        if (convert != null && convert instanceof InstanceInfo) {
                            InstanceInfo instanceInfo = (InstanceInfo) convert;
                            instanceInfoList.add(instanceInfo);
                        }
                    }
                } else if (data instanceof InstanceInfo) {
                    for (Object item : paramList) {
                        instanceInfoList.add((InstanceInfo) item);
                    }
                }
            }
        }
        return instanceInfoList;
    }


    /**
     * 根据机房Id获取机房整合后的布局
     *
     * @param ids
     * @return
     * @throws Exception
     */
    public List<MwRoomLayoutIntegration> getRoomLayoutIntegration(List<String> ids) throws Exception {
        List<MwRoomLayoutIntegration> list = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(ids)) {
            List<String> roomIds = ids;
            Map<String, Map<String, InstanceInfo>> ms = getCabinetPositionByRoomId(ids);
            List<InstanceInfo> roomInfoList = doListByIdsNotAuth(roomIds);
            for (InstanceInfo instanceInfo : roomInfoList) {
                MwRoomLayoutIntegration roomLayoutDataByRoom = new MwRoomLayoutIntegration();
                String roomId = instanceInfo.getId();
                MwRoomLayoutDataLookParam mwRoomLayoutDataParam = new MwRoomLayoutDataLookParam();
                if (instanceInfo.getData() != null && instanceInfo.getData().get(layoutDataRoom) != null) {
                    Object layoutData = instanceInfo.getData().get(layoutDataRoom);
                    //获取机房布局数据
                    mwRoomLayoutDataParam = JSONObject.parseObject(JSONObject.toJSONString(layoutData), MwRoomLayoutDataLookParam.class);
                    List<List<MwRoomLayoutLookInfo>> roomLayoutData = mwRoomLayoutDataParam.getLayoutData();
                    if (ms != null && ms.containsKey(roomId)) {
                        //获取机柜占用坐标信息
                        Map<String, InstanceInfo> positionMap = ms.get(roomId);
                        positionMap.forEach((k, v) -> {
                            String positionStr = k;
                            InstanceInfo cabinetInfo = v;
                            int XPosition = 0;
                            int YPosition = 0;
                            if (!Strings.isNullOrEmpty(positionStr) && positionStr.contains(",")) {
                                String[] split = positionStr.split(",");
                                XPosition = intValueConvert(split[0]);
                                YPosition = intValueConvert(split[1]);
                            }
                            MwRoomLayoutLookInfo mwRoomLayoutInfo = roomLayoutData.get(XPosition).get(YPosition);
                            mwRoomLayoutInfo.setIsUsed(true);
                            mwRoomLayoutInfo.setCabinetName(cabinetInfo.getInstanceName());
                            mwRoomLayoutInfo.setCabinetId(cabinetInfo.getId());
                        });
                    }
                }
                roomLayoutDataByRoom.setRoomId(roomId);
                roomLayoutDataByRoom.setRoomLayoutData(mwRoomLayoutDataParam);
                list.add(roomLayoutDataByRoom);
            }
        }
        return list;
    }

    /**
     * 根据机柜Id获取机柜整合后的布局
     *
     * @param ids
     * @return
     * @throws Exception
     */
    public List<MwCabinetLayoutIntegration> getCabinetLayoutIntegration(List<String> ids) throws Exception {
        List<MwCabinetLayoutIntegration> list = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(ids)) {
            List<String> cabinetIds = ids;
            List<InstanceInfo> cabinetInfoList = doListByIdsNotAuth(cabinetIds);
            Map<String, Map<String, InstanceInfo>> ms = getDevicePositionByCabinetId(ids, cabinetInfoList);
            for (InstanceInfo instanceInfo : cabinetInfoList) {
                MwCabinetLayoutIntegration cabinetLayoutData = new MwCabinetLayoutIntegration();
                String cabinetId = instanceInfo.getId();
                List<MwCabinetLayoutDataLookParam> cabinetLayoutDataList = new ArrayList<>();
                if (instanceInfo.getData() != null && instanceInfo.getData().get(layoutDataCabinet) != null) {
                    Object layoutData = instanceInfo.getData().get(layoutDataCabinet);
                    //获取机柜布局数据
                    cabinetLayoutDataList = JSONArray.parseArray(JSONArray.toJSONString(layoutData), MwCabinetLayoutDataLookParam.class);
                    if (ms != null && ms.containsKey(cabinetId)) {
                        //获取下属设备占用U位信息
                        Map<String, InstanceInfo> UNumMap = ms.get(cabinetId);
                        for (Map.Entry<String, InstanceInfo> entry : UNumMap.entrySet()) {
                            String k = entry.getKey();
                            InstanceInfo v = entry.getValue();
                            String UNumIndex = k;
                            InstanceInfo deviceInfo = v;
                            int UNumStart = 0;
                            int UNumEnd = 0;
                            if (!Strings.isNullOrEmpty(UNumIndex) && UNumIndex.contains("-")) {
                                String[] split = UNumIndex.split("-");
                                UNumStart = intValueConvert(split[0]);
                                UNumEnd = intValueConvert(split[1]);
                            }
                            for (int x = UNumStart; x <= UNumEnd; x++) {
                                int index = (x - 1) > 0 ? (x - 1) : 0;
                                MwCabinetLayoutDataLookParam cabinetLookParam = new MwCabinetLayoutDataLookParam();
                                cabinetLookParam.setInstanceName(deviceInfo.getInstanceName());
                                cabinetLookParam.setInstanceId(deviceInfo.getId());
                                cabinetLookParam.setIndex(x);
                                cabinetLookParam.setStatus(6);
                                cabinetLayoutDataList.set(index, cabinetLookParam);
                            }
                        }
                    }
                }
                cabinetLayoutData.setCabinetId(cabinetId);
                cabinetLayoutData.setCabinetLayoutData(cabinetLayoutDataList);
                list.add(cabinetLayoutData);
            }
        }
        return list;
    }


    /**
     * 根据机房Id获取机柜坐标和机柜信息
     *
     * @param roomIds
     * @return
     * @throws Exception
     */
    public Map<String, Map<String, InstanceInfo>> getCabinetPositionByRoomId(List<String> roomIds) throws Exception {
        //查询机房下的机柜
        List<InstanceInfo> cabinetInfoByRoomId = getInstanceListByRelationIds(roomIds, QueryCabinetByRoom);
        //机房Id 对应的机柜坐标和机柜名称
        Map<String, Map<String, InstanceInfo>> ms = new HashMap();

        //获取关联机房id对应的机柜实例数据
        Map<String, List<InstanceInfo>> cabinetInfosByRoomId = cabinetInfoByRoomId.stream().filter(s -> s.getData() != null && s.getData().get(relationRoom) != null).collect(Collectors.groupingBy(s -> strValueConvert(((Map) s.getData().get(relationRoom)).get(relationIdKey))));
        cabinetInfosByRoomId.forEach((k, v) -> {
            String roomId = k;
            List<InstanceInfo> instanceInfos = v;
            Map<String, InstanceInfo> map = new HashMap();
            for (InstanceInfo instanceInfo : instanceInfos) {
                if (instanceInfo.getData() != null) {
                    Map<String, Object> data = instanceInfo.getData();
                    if (data.get(cabinetPosition) != null && data.get(cabinetPosition) instanceof List) {
                        //获取机柜位置坐标
                        List<Integer> positionList = (List<Integer>) data.get(cabinetPosition);
                        if (CollectionUtils.isNotEmpty(positionList) && positionList.size() > 1) {
                            String positionStr = positionList.get(0) + "," + positionList.get(1);
                            map.put(positionStr, instanceInfo);
                        }
                    }
                }
            }
            ms.put(roomId, map);
        });
        return ms;
    }


    /**
     * 根据机柜Id获取机柜下属设备的布局U位
     *
     * @param cabinetIds
     * @return
     * @throws Exception
     */
    public Map<String, Map<String, InstanceInfo>> getDevicePositionByCabinetId(List<String> cabinetIds, List<InstanceInfo> cabinetInfoList) throws Exception {
        //查询机柜下的设备信息
        List<InstanceInfo> deviceInfoListByCabinetId = getInstanceListByRelationIds(cabinetIds, QueryInstanceByCabinet);
        //机柜Id对应机柜信息
        Map<String, InstanceInfo> collect = cabinetInfoList.stream().collect(Collectors.toMap(s -> s.getId(), s -> s, (k1, k2) -> k1));

        //机柜Id 对应的设备U位和设备名称
        Map<String, Map<String, InstanceInfo>> ms = new HashMap();

        //获取关联机柜id对应的实例数据
        Map<String, List<InstanceInfo>> deviceMapByCabinetId = deviceInfoListByCabinetId.stream().filter(s -> s.getData() != null && s.getData().get(relationCabinet) != null).collect(Collectors.groupingBy(s -> strValueConvert(((Map) s.getData().get(relationCabinet)).get(relationIdKey))));
        deviceMapByCabinetId.forEach((k, v) -> {
            String cabinetId = k;
            InstanceInfo cabinetInfo = new InstanceInfo();
            if (collect != null && collect.containsKey(cabinetId)) {
                cabinetInfo = collect.get(cabinetId);
            }
            String ruleType = strValueConvert(cabinetInfo.getData().get(cabinetRuleType));
            List<InstanceInfo> instanceInfos = v;
            Map<String, InstanceInfo> map = new HashMap();
            for (InstanceInfo instanceInfo : instanceInfos) {
                if (instanceInfo.getData() != null) {
                    Map<String, Object> data = instanceInfo.getData();
                    //设备高度
                    int UHeight = intValueConvert(data.get(deviceHeight)) == 0 ? 1 : intValueConvert(data.get(deviceHeight));
                    //获取U位数
                    int UNumEnd = 0;
                    if (data.get(deviceUIndex) != null) {
                        //获取下属设备U位
                        int UNumStart = intValueConvert(data.get(deviceUIndex)) + 1;
                        if (cabinetRuleTypeDownKey.equals(ruleType)) {
                            UNumEnd = UNumStart - UHeight + 1;
                        } else {
                            UNumEnd = UNumStart + UHeight - 1;
                        }
                        //mapKey值(U位数)按照重小到大的顺序
                        String key = "";
                        if (UNumStart >= UNumEnd) {
                            key = UNumEnd + "-" + UNumStart;
                        } else {
                            key = UNumStart + "-" + UNumEnd;
                        }
                        map.put(key, instanceInfo);
                    }
                }
            }
            ms.put(cabinetId, map);
        });
        return ms;
    }


    /**
     * 根据不同的查询类型获取实例信息
     *
     * @return
     */
    public List<InstanceInfo> getInstanceListByRelationIds(List<String> ids, QueryRoomCabinetType queryType) throws Exception {
        InstanceServiceImpl service = (InstanceServiceImpl) cmdbServiceManage.getModelService(InstanceServiceImpl.ID);
        Query query = queryType.query(ids);
        List<InstanceInfo> instanceInfoList = service.selectListByQuery(query);
        return instanceInfoList;
    }

    public void getInstanceAlertInfo(List<? extends InstanceInfo> listInfo) throws Exception {
//        //获取告警数据
//        List<CurrentAlertDto> alertDtos = getAlertListByInstanceInfos(listInfo, null);
//        if (CollectionUtils.isNotEmpty(alertDtos)) {
//            Map<String, List<AlertDto>> collect = new HashMap<>();
//            if (CollectionUtils.isNotEmpty(alertDtos)) {
//                collect = alertDtos.stream().filter(s -> !Strings.isNullOrEmpty(s.getInstanceId())).collect(Collectors.groupingBy(s -> s.getInstanceId()));
//            }
//
//            for (InstanceInfo info : listInfo) {
//                String id = info.getId();
//                String itemAssetsStatus = info.getItemAssetsStatus();
//                //资产状态正常的，判断是否有告警
//                if (NORMAL.getName().equals(itemAssetsStatus) && collect != null && collect.containsKey(id)) {
//                    if (CollectionUtils.isNotEmpty(collect.get(id))) {
//                        info.setItemAssetsStatus(ALERT.getName());
//                    }
//                }
//            }
//        }

    }

    /**
     * 更加资产获取当前告警数据
     *
     * @param listInfo
     * @return
     * @throws Exception
     */
    public List<CurrentAlertDto> getAlertListByInstanceInfos(List<? extends InstanceInfo> listInfo, List<String> alertList) throws Exception {
        List<String> instanceIds = new ArrayList<>();
        //查询优化，如果每次的实例数据多余100条，直接查询全部，否则就按照指定的ids查询
        if (CollectionUtils.isNotEmpty(listInfo) && listInfo.size() <= 100) {
            instanceIds = listInfo.stream().map(s -> s.getId()).collect(Collectors.toList());
        }
        long time1 = System.currentTimeMillis();
        List<String> list = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(alertList)) {
            list = alertList;
        } else {
            list = alertLevelList;
        }
        List<CurrentAlertDto> alertDtos = getAlertDtosByInstanceIds(instanceIds, list);
        long time2 = System.currentTimeMillis();
        log.info("getCurrentAlertInfoByInstanceIds耗时::" + (time2 - time1) + "ms;告警list大小:" + alertDtos.size());
        return alertDtos;
    }

    public List<CurrentAlertDto> getAlertDtosByInstanceIds(List<String> instanceIds, List<String> alertList) throws Exception {
        List<String> list = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(alertList)) {
            list = alertList;
        } else {
            list = alertLevelList;
        }
        List<CurrentAlertDto> alertDtos = alertApiService.getCurrentAlertInfoByInstanceIds(instanceIds, list);
        return alertDtos;
    }


    /**
     * 修改通知
     *
     * @param map
     * @param param
     * @throws Exception
     */
    public Object notifyUpdateChangeFunction(Map<String, Object> map, Object param) throws Exception {
        InstanceListenersManager manager = new InstanceListenersManager();
        ContextEditorListener contextListener = new ContextEditorListener();
        contextListener.setMap(map);
        contextListener.setParam(param);
        manager.addListerList(listerList);
        Object o = manager.notifyLister(contextListener);
        return o;
    }

    /**
     * 新增通知
     *
     * @param map
     * @param param
     * @throws Exception
     */
    public void notifyAddChangeFunction(Map<String, Object> map, Object param) throws Exception {
        InstanceListenersManager manager = new InstanceListenersManager();
        ContextAddListener contextListener = new ContextAddListener();
        contextListener.setMap(map);
        contextListener.setParam(param);
        manager.addListerList(listerList);
        manager.notifyLister(contextListener);
    }

    /**
     * 删除通知
     *
     * @param map
     * @param param
     * @throws Exception
     */
    public void notifyDeleteChangeFunction(Map<String, Object> map, Object param) throws Exception {
        InstanceListenersManager manager = new InstanceListenersManager();
        ContextDeleteListener contextListener = new ContextDeleteListener();
        contextListener.setMap(map);
        contextListener.setParam(param);
        manager.addListerList(listerList);
        manager.notifyLister(contextListener);
    }

    /**
     * 根据U位管理的标签Id查询资产
     * 标签Id和实例一一对应
     *
     * @param tagIds
     * @return
     * @throws Exception
     */
    public List<InstanceInfo> doListByTagIdsNotAuth(List<String> tagIds) throws Exception {
        List<InstanceInfo> ret = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(tagIds)) {
            Query query = new Query(CriteriaWrapper.where(InstanceInfo::getDelFlag).is(false));
            query.addCriteria(Criteria.where(tagUManageIdPath).in(tagIds));
            ret = instanceInfoMapper.find(query);
        }
        return ret;
    }

    /**
     * 导入修改唯一值查询校验
     */
    public Map<String, Map> importMatchCheck(List<ModelExportDataInfoParam> allDataList, Map<Integer, String> rowNumByModelIdMap, List<InstanceImportResultInfo> instanceImportResultInfoList) throws Exception {
        QueryImportMachFieldInfo fieldInfo = new QueryImportMachFieldInfo();
        Map<String, Map> collect = new HashMap<>();
        Map<String, Integer> dataByRowNum = new HashMap<>();
        Set<String> disValues = new HashSet<>();
        if (CollectionUtils.isNotEmpty(allDataList)) {
            List<ModelExportDataInfoParam> importDataInfos = allDataList.stream().filter(s -> s.getIsMatchKey() != null && s.getIsMatchKey()).collect(Collectors.toList());
            Map<String, List<ModelExportDataInfoParam>> collectDis = importDataInfos.stream().filter(s -> s.getRowNum() != 0 && !Strings.isNullOrEmpty(strValueConvert(s.getCellValue()))).collect(Collectors.groupingBy(s -> strValueConvert(s.getCellValue())));
            for (Map.Entry<String, List<ModelExportDataInfoParam>> entry : collectDis.entrySet()) {
                String k = entry.getKey();
                List<ModelExportDataInfoParam> v = entry.getValue();
                List<ModelExportDataInfoParam> listData = v;
                if (CollectionUtils.isNotEmpty(listData) && listData.size() > 1) {
                    for (ModelExportDataInfoParam infoParam : listData) {
                        InstanceImportResultInfo instanceImportResultInfo = new InstanceImportResultInfo();
                        instanceImportResultInfo.setInstanceName("");
                        instanceImportResultInfo.setInstanceId("");
                        instanceImportResultInfo.setModelId("");
                        instanceImportResultInfo.setFinanceParentModelId(infoParam.getFinanceParentId());
                        instanceImportResultInfo.setResult(false);
                        instanceImportResultInfo.setErrorMsg("唯一标识:" + infoParam.getTableName() + "[" + infoParam.getCellValue() + "]重复");
                        instanceImportResultInfo.setRowIndex("第" + (infoParam.getRowNum() + 1) + "行");
                        if (instanceImportResultInfoList == null) {
                            instanceImportResultInfoList = new ArrayList<>();
                        }
                        instanceImportResultInfoList.add(instanceImportResultInfo);
                        disValues.add(strValueConvert(infoParam.getCellValue()));
                    }
                }
            }
            dataByRowNum = importDataInfos.stream().filter(s -> s.getRowNum() != 0 && !Strings.isNullOrEmpty(strValueConvert(s.getCellValue())) && !disValues.contains(strValueConvert(s.getCellValue()))).collect(Collectors.toMap(s -> strValueConvert(s.getCellValue()), s -> s.getRowNum(), (
                    value1, value2) -> {
                return value2;
            }));

            List<ModelExportDataInfoParam> disDataInfoParams = importDataInfos.stream().filter(s -> s.getRowNum() != 0 && !Strings.isNullOrEmpty(strValueConvert(s.getCellValue())) && !disValues.contains(strValueConvert(s.getCellValue()))).collect(Collectors.toList());

            if (CollectionUtils.isNotEmpty(disDataInfoParams)) {
                ModelExportDataInfoParam dataInfoParam = disDataInfoParams.get(0);
                String propertyId = dataInfoParam.getPropertyId();
                List<String> values = disDataInfoParams.stream().map(s -> strValueConvert(s.getCellValue())).collect(Collectors.toList());
                fieldInfo.setValues(values);
                fieldInfo.setMatchPropertyId(propertyId);

                InstanceSearchParam instanceSearchParam = new InstanceSearchParam();
                SubCondition subCondition = new SubCondition(CriteriaOpsType.in.name(), values);
                instanceSearchParam.addSubCondition(propertyId, subCondition);

                instanceSearchParam.convert();
                Criteria criteria = doCriteria(instanceSearchParam);
                List<Map> mapList = new ArrayList<>();
                if (criteria != null) {
                    Query query = new Query(criteria);
                    List<InstanceInfo> instanceInfoList = doListByQueryNotAuth(query);
                    for (InstanceInfo instanceInfo : instanceInfoList) {
                        Map map = beanToMap(instanceInfo);
                        Map m = (Map) map.get(SearchPrefix);
                        map.putAll(m);
                        mapList.add(map);
                    }
                }
                collect = mapList.stream().filter(s -> s.get(propertyId) != null).collect(Collectors.toMap(s -> strValueConvert(s.get(propertyId)), s -> s, (
                        value1, value2) -> {
                    return value2;
                }));
            }
        }

        Map<String, Integer> finalDataByRowNum = dataByRowNum;
        collect.forEach((k, v) -> {
            if (finalDataByRowNum != null) {
                Integer rowNum = finalDataByRowNum.get(k);
                Map mapInfo = v;
                String modelId = strValueConvert(mapInfo.get(modelIdKey));
                rowNumByModelIdMap.put(rowNum, modelId);
            }
        });
        return collect;
    }

    /**
     * 插入资产编码缓存数据
     * 根据模型Code和年月 每次插入20条数据
     *
     * @return
     */
    public List<AssetsCodeCacheDTO> insertAssetsCodeCache(String modelCode, Integer num) throws Exception {
        //设置线程锁，确保多线程并发时，创建的资产编码唯一
        lock.lock();
        List<AssetsCodeCacheDTO> assetCodeList = new ArrayList<>();
        try {
            if (!Strings.isNullOrEmpty(modelCode)) {
                for (int i = 0; i < num; i++) {
                    AssetsCodeCacheDTO dto = new AssetsCodeCacheDTO();
                    String assetCode = getIMDateId(modelCode);
                    dto.setAssetsCode(assetCode);
                    assetCodeList.add(dto);
                }
            }
            if (CollectionUtils.isNotEmpty(assetCodeList)) {
                assetsCodeCacheMapper.insert(assetCodeList);
            }
        } finally {
            lock.unlock();
        }
        return assetCodeList;
    }

    public String getAssetsCodeCacheStr(String modelId) throws Exception {
        return getIMDateIdNoShow(modelId);
    }


//    public String getAssetsCodeCacheStr(String modelId) throws Exception {
//        List<AssetsCodeCacheDTO> assetsCodeCacheList = getAssetsCodeCacheList(modelId);
//        String assetsCode = "";
//        if (CollectionUtils.isNotEmpty(assetsCodeCacheList)) {
//            Set<String> collect = assetsCodeCacheList.stream().filter(s -> !Strings.isNullOrEmpty(s.getAssetsCode())).map(s -> s.getAssetsCode()).collect(Collectors.toSet());
//            List<String> list = collect.stream().sorted().collect(Collectors.toList());
//            if (CollectionUtils.isNotEmpty(list)) {
//                //取出一个就删除
//                assetsCode = list.get(0);
//                deleteAssetsCodeCacheList(Arrays.asList(assetsCode));
//            }
//        }
//        return assetsCode;
//    }

    public List<String> getAssetsCodeCacheStr(String modelId, int num) throws Exception {
        List<AssetsCodeCacheDTO> assetsCodeCacheList = getAssetsCodeCacheList(modelId, num);
        List<String> listInfos = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(assetsCodeCacheList)) {
            Set<String> collect = assetsCodeCacheList.stream().filter(s -> !Strings.isNullOrEmpty(s.getAssetsCode())).map(s -> s.getAssetsCode()).collect(Collectors.toSet());
            List<String> list = collect.stream().sorted().collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(list) && list.size() >= num) {
                //取出对应数量的资产编码
                listInfos = list.subList(0, num);
                //删除对应的资产编码
                deleteAssetsCodeCacheList(listInfos);
            }
        }
        return listInfos;
    }

    /**
     * 获取资产编码缓存数据
     *
     * @return
     */
    public List<AssetsCodeCacheDTO> getAssetsCodeCacheList(String modelId, int num) throws Exception {
        lock.lock();
        List<AssetsCodeCacheDTO> dtoList = new ArrayList<>();
        List<AssetsCodeCacheDTO> dtoAllList = new ArrayList<>();
        try {
            String modelCode = getModelCodeCheck(modelId);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");
            String nowStr = sdf.format(new Date());
            //四级编码
            String fourLevelCode = "00";
            String threeLevelCode = "";
            if (modelCode.length() == 6) {
                fourLevelCode = "00";
                threeLevelCode = modelCode;
            } else if (modelCode.length() == 8) {
                fourLevelCode = modelCode.substring(modelCode.length() - 2);
                threeLevelCode = modelCode.substring(0, 6);
            } else {
                return null;
            }
            int addNum = num;
            String codeKey = threeLevelCode + "-" + nowStr + "-" + fourLevelCode;
            Query query = new Query();
            query.addCriteria(CriteriaWrapper.where(AssetsCodeCacheDTO::getAssetsCode).regex(codeKey));
            //先查询数据库中是否有缓存的资产编码
            dtoList = assetsCodeCacheMapper.find(query);
            dtoAllList.addAll(dtoList);
            if (CollectionUtils.isNotEmpty(dtoList)) {
                if (dtoList.size() < num) {
                    addNum = num - dtoList.size();
                    dtoList.clear();
                }
            }
            //没有数据，先新增资产编码
            if (addNum > 0) {
                dtoAllList.addAll(insertAssetsCodeCache(modelCode, addNum));
            }

        } finally {
            lock.unlock();
        }
        return dtoAllList;
    }


    /**
     * 获取资产编码缓存数据
     *
     * @return
     */
    public List<AssetsCodeCacheDTO> getAssetsCodeCacheList(String modelId) throws Exception {
        lock.lock();
        List<AssetsCodeCacheDTO> dtoList = new ArrayList<>();
        try {
            String modelCode = getModelCodeCheck(modelId);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMM");
            String nowStr = sdf.format(new Date());
            //四级编码
            String fourLevelCode = "00";
            String threeLevelCode = "";
            if (modelCode.length() == 6) {
                fourLevelCode = "00";
                threeLevelCode = modelCode;
            } else if (modelCode.length() == 8) {
                fourLevelCode = modelCode.substring(modelCode.length() - 2);
                threeLevelCode = modelCode.substring(0, 6);
            } else {
                return null;
            }
            String codeKey = threeLevelCode + "-" + nowStr + "-" + fourLevelCode;
            Query query = new Query();
            query.addCriteria(CriteriaWrapper.where(AssetsCodeCacheDTO::getAssetsCode).regex(codeKey));
            //先查询数据库中是否有缓存的资产编码
            dtoList = assetsCodeCacheMapper.find(query);
            if (CollectionUtils.isNotEmpty(dtoList)) {
                dtoList.removeAll(assetsCodeCacheThreadAllList);
            }
            //没有数据，先新增资产编码
            if (CollectionUtils.isEmpty(dtoList)) {
                dtoList = insertAssetsCodeCache(modelCode, BATCH_SIZE);
            }
//            List<String> codeLists = dtoList.stream().map(s -> s.getAssetsCode()).collect(Collectors.toList());
            //按模型Id存放对应的资产编码List
//            assetsCodeCacheThreadMap.put(modelId, codeLists);
//            //获取所有创建的资产编码记录
//            assetsCodeCacheThreadAllList.addAll(dtoList);
        } finally {
            lock.unlock();
        }

        return dtoList;
    }

    /**
     * 插入资产编码缓存数据
     *
     * @return
     */
    public boolean insertAssetsCodeCacheList(List<String> assetsCodeList) throws Exception {
        List<AssetsCodeCacheDTO> insertList = new ArrayList<>();
        lock.lock();
        try {
            if (CollectionUtils.isNotEmpty(assetsCodeList)) {
                for (String code : assetsCodeList) {
                    AssetsCodeCacheDTO dto = new AssetsCodeCacheDTO();
                    dto.setAssetsCode(code);
                    insertList.add(dto);
                }
                assetsCodeCacheMapper.insert(insertList);
            }
        } finally {
            lock.unlock();
        }
        return true;
    }

    /**
     * 删除资产编码缓存数据
     *
     * @return
     */
    public boolean deleteAssetsCodeCacheList(List<String> assetsCodeList) throws Exception {
        Query query = new Query();
        query.addCriteria(CriteriaWrapper.where(AssetsCodeCacheDTO::getAssetsCode).in(assetsCodeList));
        assetsCodeCacheMapper.remove(query);
        return true;
    }


    /**
     * 删除资产编码缓存数据
     *
     * @return
     */
    public boolean deleteAssetsCodeByQuery(Query query) throws Exception {
        assetsCodeCacheMapper.remove(query);
        return true;
    }

    public void importDataBatchUpdate(List<InstanceInfo> instanceInfoList, ModelExportDataInfoListParam param, BatchAddAndUpdInstanceParam batchAddAndUpdInstanceParam) throws Exception {
        InstanceInfoAddConsumer instanceInfoAddConsumer = new InstanceInfoAddConsumer();
        batchAddAndUpdInstance(instanceInfoList, false, instanceInfoAddConsumer, batchAddAndUpdInstanceParam);
    }

    /**
     * 新增异常日志记录
     *
     * @param param
     */
    public void addRecordMethod(Object param) {
        String name = "";
        if (param != null && param instanceof InstanceInfo) {
            InstanceInfo info = (InstanceInfo) param;
            name = info.getInstanceName();
        }
        String nickName = SecurityUtils.getUser().getNickName();
        MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
        logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.CMDB_MANAGE.getId(),
                messageSource.getMessage("mwCmdb-operation-log", new Object[]{nickName, DateUtils.now()
                        , BusinessLogType.CMDB_MANAGE.getCnName(), OperatorTypeDescEnum.add.getCname() + Modelinstance.getDesc(),
                        OperatorTypeDescEnum.add.getCname() + name, Constants.OperationStatus.FAILED}, LocaleContextHolder.getLocale()));
    }

    /**
     * 修改异常日志记录
     *
     * @param param
     */
    public void updateRecordMethod(Object param) {
        String name = "";
        if (param != null && param instanceof InstanceInfo) {
            InstanceInfo info = (InstanceInfo) param;
            name = info.getInstanceName();
        }
        String nickName = SecurityUtils.getUser().getNickName();
        MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
        logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.CMDB_MANAGE.getId(),
                messageSource.getMessage("mwCmdb-operation-log", new Object[]{nickName, DateUtils.now()
                        , BusinessLogType.CMDB_MANAGE.getCnName(), OperatorTypeDescEnum.update.getCname() + Modelinstance.getDesc(),
                        OperatorTypeDescEnum.update.getCname() + name, Constants.OperationStatus.FAILED}, LocaleContextHolder.getLocale()));
    }

    /**
     * 删除异常日志记录
     *
     * @param param
     */
    private void removeRecordMethod(Object param) {
        String name = "";
        if (param != null && param instanceof InstanceInfo) {
            InstanceInfo info = (InstanceInfo) param;
            name = info.getInstanceName();
        }
        String nickName = SecurityUtils.getUser().getNickName();
        MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
        logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.CMDB_MANAGE.getId(),
                messageSource.getMessage("mwCmdb-operation-log", new Object[]{nickName, DateUtils.now()
                        , BusinessLogType.CMDB_MANAGE.getCnName(), OperatorTypeDescEnum.remove.getCname() + Modelinstance.getDesc(),
                        OperatorTypeDescEnum.remove.getCname() + name, Constants.OperationStatus.FAILED}, LocaleContextHolder.getLocale()));
    }

    /**
     * 批量新增异常日志记录
     *
     * @param params
     */
    private void batchAddRecordMethod(Object params) {
        String name = "";
        if (params instanceof List) {
            List<InstanceInfo> paramList = (List<InstanceInfo>) params;
            List<String> collect = paramList.stream().map(s -> s.getInstanceName()).collect(Collectors.toList());
            name = String.join(",", collect);
        }
        String nickName = SecurityUtils.getUser().getNickName();
        MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
        logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.CMDB_MANAGE.getId(),
                messageSource.getMessage("mwCmdb-operation-log", new Object[]{nickName, DateUtils.now()
                        , BusinessLogType.CMDB_MANAGE.getCnName(), OperatorTypeDescEnum.batchAdd.getCname() + Modelinstance.getDesc(),
                        OperatorTypeDescEnum.batchAdd.getCname() + name, Constants.OperationStatus.FAILED}, LocaleContextHolder.getLocale()));

    }

    /**
     * 批量修改异常日志记录
     *
     * @param params
     */
    private void batchUpdateRecordMethod(Object params) {
        String name = "";
        String nickName = SecurityUtils.getUser().getNickName();
        MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
        logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.CMDB_MANAGE.getId(),
                messageSource.getMessage("mwCmdb-operation-log", new Object[]{nickName, DateUtils.now()
                        , BusinessLogType.CMDB_MANAGE.getCnName(), OperatorTypeDescEnum.batchUpd.getCname() + Modelinstance.getDesc(),
                        OperatorTypeDescEnum.batchUpd.getCname() + name, Constants.OperationStatus.FAILED}, LocaleContextHolder.getLocale()));

    }

    /**
     * 批量删除异常日志记录
     *
     * @param param
     */
    private void batchRemoveRecordMethod(Object param) throws Exception {
        InstanceIdsParam params = (InstanceIdsParam) param;
        String name = "";
        List<InstanceInfo> instanceInfoList = doListByIdsNotAuth(params.getIds());
        List<String> collect = instanceInfoList.stream().map(s -> s.getInstanceName()).collect(Collectors.toList());
        name = String.join(",", collect);
        String nickName = SecurityUtils.getUser().getNickName();
        MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
        logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.CMDB_MANAGE.getId(),
                messageSource.getMessage("mwCmdb-operation-log", new Object[]{nickName, DateUtils.now()
                        , BusinessLogType.CMDB_MANAGE.getCnName(), OperatorTypeDescEnum.batchRemove.getCname() + Modelinstance.getDesc(),
                        OperatorTypeDescEnum.batchRemove.getCname() + name, Constants.OperationStatus.FAILED}, LocaleContextHolder.getLocale()));

    }

    public void updateDeviceCode(DeviceCodeParam deviceCodeParam) throws Exception {
        Query query = null;
        if (deviceCodeParam.isUpdateAll()) {
            query = new Query();
        } else {
            query = new Query(CriteriaWrapper.where(InstanceInfo::getId).in(deviceCodeParam.getInstanceIds()));
        }

        query.addCriteria(CriteriaWrapper.where(InstanceInfo::getDeviceCode).ne(null));
        List<InstanceInfo> instanceInfos = selectListByQuery(query);
        if (null != instanceInfos) {
            BusinessProcessNetwork businessProcessNetwork = SpringUtils.getBean(BusinessProcessNetwork.class);
            List<DeviceInfoView> deviceInfoViews = businessProcessNetwork.getInterfacedeviceInfoViews(instanceInfos);
            if (null != deviceInfoViews) {
                Map<String, DeviceInfoView> deviceInfoViewMap = new HashMap<>();
                for (DeviceInfoView deviceInfoView : deviceInfoViews) {
                    if (StringUtils.isNotEmpty(deviceInfoView.getDeviceIP())) {
                        deviceInfoViewMap.put(deviceInfoView.getDeviceIP(), deviceInfoView);
                    }
                }

                List<InstanceInfo> updateInstanceInfos = new ArrayList<>();
                for (InstanceInfo instanceInfo : instanceInfos) {
                    DeviceInfoView deviceInfoView = deviceInfoViewMap.get(instanceInfo.getInBandIp());
                    String deviceCode = deviceInfoView.getDeviceIDCode();
                    if (null != instanceInfo.getDeviceCode() && StringUtils.isNotEmpty(deviceCode)
                            && !instanceInfo.getDeviceCode().equals(deviceCode)) {
                        InstanceInfo item = new InstanceInfo();
                        item.setId(instanceInfo.getId());
                        item.setDeviceCode(deviceCode);
                        updateInstanceInfos.add(item);
                    }
                }

                BulkOperations operations = instanceInfoMapper.bulkOps(BulkOperations.BulkMode.UNORDERED, InstanceInfo.class);
                for (InstanceInfo instanceInfo : updateInstanceInfos) {
                    Pair<Query, Update> queryUpdatePair = convertUpdateByInstance(instanceInfo);
                    operations.updateMulti(queryUpdatePair.getFirst(), queryUpdatePair.getSecond());
                }

                if (!updateInstanceInfos.isEmpty()) {
                    operations.execute();
                }

                log.info(updateInstanceInfos.toString());
            }
        }
    }

    /**
     * 根据实例id修改资产监控状态
     *
     * @param instanceId
     * @throws Exception
     */
    public void updateInstanceAlertStatus(String instanceId) throws Exception {
        if (!Strings.isNullOrEmpty(instanceId)) {
            Query query = new Query(CriteriaWrapper.where(InstanceInfo::getId).is(instanceId));
            Update update = new Update().set(CMDBTool.getFieldName(InstanceInfo::getItemAssetsStatus), ALERT.getName());
            log.info("updateInstanceAlertStatus::coming::" + query + ";update" + update);
            instanceInfoMapper.updateFirst(query, update);
        }
    }

    /**
     * 恢复资产监控状态
     *
     * @param instanceId
     * @throws Exception
     */
    public void recoverInstanceMonitorStatus(String instanceId) throws Exception {
        if (!Strings.isNullOrEmpty(instanceId)) {
            List<CurrentAlertDto> alertInfoInstanceIds = getAlertDtosByInstanceIds(Arrays.asList(instanceId), null);
            if (CollectionUtils.isEmpty(alertInfoInstanceIds)) {
                Query query = new Query(CriteriaWrapper.where(InstanceInfo::getId).is(instanceId));
                Update update = new Update().set(CMDBTool.getFieldName(InstanceInfo::getItemAssetsStatus), NORMAL.getName());
                log.info("recoverInstanceMonitorStatus::coming::" + query + ";update" + update);
                instanceInfoMapper.updateFirst(query, update);
            }
        }
    }

    private MwCmdbTriggerManager getMwCmdbTriggerManager() {
        return MwCmdbTriggerManager.getMwCmdbTriggerManager();
    }

    public void batchUpdateMonitorProxy(List instanceList, Integer proxyType, String pollingEngine) throws Exception {
        AssetsManageServiceImpl bean = SpringUtils.getBean(AssetsManageServiceImpl.class);
        Map proxyIdMap = bean.getProxyDataByPollingEngine(instanceList);
        String proxyId = null;
        if (!Strings.isNullOrEmpty(pollingEngine) && proxyIdMap != null) {
            proxyId = proxyIdMap.get(pollingEngine) == null ? null : strValueConvert(proxyIdMap.get(pollingEngine));
        }

        MwInstanceMonitorManage monitorManage = new MwInstanceMonitorManage(zabbixDubboService);
        List<QueryMonitorValue> queryMonitorParamList = monitorManage.zabbixParamListConvert(instanceList);
        for (QueryMonitorValue queryMonitorParam : queryMonitorParamList) {
            queryMonitorParam.setMwProxyType(proxyType);
            queryMonitorParam.setMwProxyId(proxyId);
        }
        monitorManage.handlerMonitorMethodThread(queryMonitorParamList, null, batchEditorProxyValue.getName());
    }

    public void updateHostMonitorIpInfo(InstanceInfo instanceInfo) throws Exception {
        Integer monitorServerId = instanceInfo.getMonitorServerId();
        String hostId = instanceInfo.getMonitorTypeId();
        //监控纳管的数据才能修改zabbix的Ip新增
        if ((monitorServerId != null && monitorServerId.intValue() != 0) && (!Strings.isNullOrEmpty(hostId) && !"0".equals(hostId))) {
            String inBandIp = instanceInfo.getInBandIp();
            MwMonitorProcessorConvert processorConvert = new MwMonitorProcessorConvert(cmdbServiceManage, zabbixDubboService);
            QueryMonitorParam queryMonitorParam = new QueryMonitorParam();
            queryMonitorParam.setMonitorServerId(instanceInfo.getMonitorServerId());
            queryMonitorParam.setHostId(instanceInfo.getMonitorTypeId());
            //获取查询监控参数context
            MonitorParamContext contextParam = processorConvert.getContextParam(inBandIp, null);
            contextParam.setQueryMonitorParam(queryMonitorParam);
            //获取查询监控processor
            MonitorProcessor processor = processorConvert.getMonitorProcessor(instanceInfo.getId());
            if (processor != null) {
                processor.updateHostIpInfo(contextParam);
            }
        }

    }

    public void getMaxInfoByAssetCode(String codeStr) {
        Query query = new Query();
        query.addCriteria(Criteria.where(mwAssetCodingKey).exists(true));
        query.addCriteria(Criteria.where(mwAssetCodingKey).regex(codeStr));
        query.with(Sort.by(Sort.Direction.DESC, mwAssetCodingKey));
        query.limit(1);
        List<InstanceInfo> instanceInfos = instanceInfoMapper.find(query);
    }

    private List<InstanceCountTrendDto> getInstanceCountTrendList(InstanceTrendSearchParam param, String timeField, boolean needDelFlag) throws Exception {

        Criteria criteria = genCriteria(param);
        GroupSearchOperation groupSearchOperation = new GroupSearchOperation();
        Document document = new Document();
        if (StringUtils.isNotEmpty(param.getCalcDimension())) {
            // 判断属性是否是data内属性
            if (isDataProperty(param.getCalcDimension())) {
                document.append(param.getCalcDimension(), String.format("$data.%s", param.getCalcDimension()));
            } else {
                document.append(param.getCalcDimension(), String.format("$%s", param.getCalcDimension()));
            }
        }
        if (needDelFlag) {
            document.append(DatabaseUtils.getFieldName(InstanceCountTrendDto::getDelFlag), String.format("$%s", DatabaseUtils.getFieldName(InstanceCountTrendDto::getDelFlag)));
        }
        document.append(DatabaseUtils.getFieldName(InstanceCountTrendDto::getYear), new Document("$year", timeField))
                .append(DatabaseUtils.getFieldName(InstanceCountTrendDto::getMonth), new Document("$month", timeField))
                .append(DatabaseUtils.getFieldName(InstanceCountTrendDto::getDay), new Document("$dayOfMonth", timeField))
                .append(DatabaseUtils.getFieldName(InstanceCountTrendDto::getHour), new Document("$hour", timeField));
        groupSearchOperation.addGroupOperationMap("_id", document);
        groupSearchOperation.addCalculateField(CMDBTool.getFieldName(InstanceCountTrendDto::getCount), GroupCalculateMethodEnum.count, "sf");
        List<InstanceCountTrendDto> result = CMDBTool.selectCountByAggregate(InstanceCountTrendDto.class, assetsInterfaceMapper, criteria, groupSearchOperation);
        return result;
    }

    private boolean isDataProperty(String fieldName) {
        List<Field> allFields = MongoUtils.getAllFields(InstanceCountTrendDto.class);
        for (Field field : allFields) {
            if (StringUtils.equals(field.getName(), fieldName)) {
                return false;
            }
        }
        return true;
    }

    public Object calcInstanceCountTrend(InstanceTrendSearchParam param) throws Exception {
        param.setSearchClass(InstanceCountTrendDto.class);
        String createTimeField = String.format("$%s", DatabaseUtils.getFieldName(InstanceCountTrendDto::getCreateTime));
        // 查询所有创建实例数量
        List<InstanceCountTrendDto> result = new ArrayList<>();
        result.addAll(getInstanceCountTrendList(param, createTimeField, false));

        // 查询删除实例数量
        param.addSubCondition(CMDBTool.getFieldName(InstanceCountTrendDto::getDelFlag), new SubCondition(CriteriaOpsType.is.name(), true));
        String deleteTimeField = String.format("$%s", DatabaseUtils.getFieldName(InstanceCountTrendDto::getModificationTime));
        result.addAll(getInstanceCountTrendList(param, deleteTimeField, true));

        List<InstanceCountTrendView> instanceCountTrendViews = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(result)) {
            Map<String, Object> groupDate;
            for (InstanceCountTrendDto instanceCountTrendDto : result) {
                groupDate = JSON.parseObject(instanceCountTrendDto.getId(), Map.class);
                instanceCountTrendDto.setGroupDate(groupDate);
            }

            InstanceCountTrendView instanceCountTrendView;
            // 按照维度统计数量
            if (StringUtils.isNotEmpty(param.getCalcDimension())) {
                Map<String, List<InstanceCountTrendDto>> dimension2CountMap;
                dimension2CountMap = result.stream().collect(Collectors.groupingBy(item -> {
                    Object calcDimension = item.getGroupDate().getOrDefault(param.getCalcDimension(), "");
                    if (calcDimension instanceof String) {
                        return (String) calcDimension;
                    } else if (calcDimension instanceof Map) {
                        return ((Map) calcDimension).getOrDefault(relationNameSuffix, "").toString();
                    }
                    return "";
                }));
                for (Map.Entry<String, List<InstanceCountTrendDto>> entry : dimension2CountMap.entrySet()) {
                    instanceCountTrendView = new InstanceCountTrendView();
                    instanceCountTrendView.setDimension(entry.getKey());

                    // 排序+数量汇总
                    Collections.sort(entry.getValue(), (o1, o2) -> {
                        String[] key1Arr = new String[]{String.valueOf(o1.getGroupDate().getOrDefault(
                                DatabaseUtils.getFieldName(InstanceCountTrendDto::getYear), "0")),
                                String.valueOf(o1.getGroupDate().getOrDefault(DatabaseUtils.getFieldName(InstanceCountTrendDto::getMonth), "0")),
                                String.valueOf(o1.getGroupDate().getOrDefault(DatabaseUtils.getFieldName(InstanceCountTrendDto::getDay), "0")),
                                String.valueOf(o1.getGroupDate().getOrDefault(DatabaseUtils.getFieldName(InstanceCountTrendDto::getHour), "0"))};
                        String[] key2Arr = new String[]{String.valueOf(o2.getGroupDate().getOrDefault(
                                DatabaseUtils.getFieldName(InstanceCountTrendDto::getYear), "0")),
                                String.valueOf(o2.getGroupDate().getOrDefault(DatabaseUtils.getFieldName(InstanceCountTrendDto::getMonth), "0")),
                                String.valueOf(o2.getGroupDate().getOrDefault(DatabaseUtils.getFieldName(InstanceCountTrendDto::getDay), "0")),
                                String.valueOf(o2.getGroupDate().getOrDefault(DatabaseUtils.getFieldName(InstanceCountTrendDto::getHour), "0"))};
                        for (int i = 0; i < key1Arr.length; i++) {
                            if (key1Arr[i] != null && key2Arr[i] != null && !key1Arr[i].equals(key2Arr[i])) {
                                return Integer.valueOf(key1Arr[i]).compareTo(Integer.valueOf(key2Arr[i]));
                            }
                        }
                        return -1;
                    });
                    int totalCount = 0;
                    for (int i = 0; i < entry.getValue().size(); i++) {
                        boolean delFlag = Boolean.valueOf(entry.getValue().get(i).getGroupDate().getOrDefault(
                                CMDBTool.getFieldName(InstanceCountTrendDto::getDelFlag), "false").toString());
                        if (delFlag) {
                            totalCount -= entry.getValue().get(i).getCount();
                        } else {
                            totalCount += entry.getValue().get(i).getCount();
                        }
                        entry.getValue().get(i).setCount(totalCount);
                    }

                    // 所选时间过滤
                    filterDataByDate(param.getFilterDate(), entry.getValue());

                    setInstanceCountSubView(instanceCountTrendView, entry.getValue(), param);
                    if (CollectionUtils.isEmpty(param.getFilterDate()) || param.getFilterDate().size() != 2) {
                        // 未设置时间范围不加载趋势数据
                        instanceCountTrendView.setSubViews(null);
                        // 名称为空，且没有资产时，不在列表显示
                        if (StringUtils.isEmpty(instanceCountTrendView.getDimension()) && instanceCountTrendView.getCount() == 0) {
                            continue;
                        }
                    }
                    instanceCountTrendViews.add(instanceCountTrendView);
                }
            } else {
                // 未设置维度时统计资产总数
                return dealWithInstanceCountCalc(result);
            }
        }
        return instanceCountTrendViews;
    }

    private InstanceCountTrendView dealWithInstanceCountCalc(List<InstanceCountTrendDto> result) {
        InstanceCountTrendView instanceCountTrendView = new InstanceCountTrendView();
        int totalCount = 0;


        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        // 当天
        LocalDateTime todayBeginDate = LocalDateTime.parse(DateUtils.now(), formatter).withHour(0).withMinute(0).withSecond(0);
        LocalDateTime todayEndDate = LocalDateTime.parse(DateUtils.now(), formatter).withHour(23).withMinute(59).withSecond(59);

        // 前一天
        LocalDateTime yesterDayBeginDate = todayBeginDate.minusDays(1);
        LocalDateTime yesterEndDate = todayEndDate.minusDays(1);

        // 本周第一天
        LocalDateTime firstDayOfWeekBeginDate = todayBeginDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY));

        LocalDateTime dateTime;
        int todayAdd = 0;
        int yesterdayAdd = 0;
        int weekAdd = 0;
        for (InstanceCountTrendDto instanceCountTrendDto : result) {
            boolean delFlag = Boolean.valueOf(instanceCountTrendDto.getGroupDate().getOrDefault(
                    CMDBTool.getFieldName(InstanceCountTrendDto::getDelFlag), "false").toString());
            if (delFlag) {
                totalCount -= instanceCountTrendDto.getCount();
            } else {
                totalCount += instanceCountTrendDto.getCount();
            }
            int year = Integer.parseInt(instanceCountTrendDto.getGroupDate().getOrDefault(DatabaseUtils.getFieldName(InstanceCountTrendDto::getYear), "1991").toString());
            int month = Integer.parseInt(instanceCountTrendDto.getGroupDate().getOrDefault(DatabaseUtils.getFieldName(InstanceCountTrendDto::getMonth), "1").toString());
            int day = Integer.parseInt(instanceCountTrendDto.getGroupDate().getOrDefault(DatabaseUtils.getFieldName(InstanceCountTrendDto::getDay), "1").toString());
            int hour = Integer.parseInt(instanceCountTrendDto.getGroupDate().getOrDefault(DatabaseUtils.getFieldName(InstanceCountTrendDto::getHour), "1").toString());
            dateTime = LocalDateTime.of(year, month, day, hour, 0);
            // 本周之前的数据不统计
            if (dateTime.isBefore(firstDayOfWeekBeginDate)) {
                continue;
            }
            // 计算本周新增实例数量
            if (delFlag) {
                weekAdd -= instanceCountTrendDto.getCount();
            } else {
                weekAdd += instanceCountTrendDto.getCount();
            }
            // 计算昨天新增实例数量
            if (dateTime.isAfter(yesterDayBeginDate) && dateTime.isBefore(yesterEndDate)) {
                if (delFlag) {
                    yesterdayAdd -= instanceCountTrendDto.getCount();
                } else {
                    yesterdayAdd += instanceCountTrendDto.getCount();
                }
            } else if (dateTime.isAfter(todayBeginDate)) {
                // 计算当天新增实例数量
                if (delFlag) {
                    todayAdd -= instanceCountTrendDto.getCount();
                } else {
                    todayAdd += instanceCountTrendDto.getCount();
                }
            }
        }
        instanceCountTrendView.setTodayAdd(todayAdd);
        instanceCountTrendView.setYesterdayAdd(yesterdayAdd);
        instanceCountTrendView.setWeekAdd(weekAdd);
        instanceCountTrendView.setCount(totalCount);
        return instanceCountTrendView;
    }

    private void filterDataByDate(List<String> filterDate, List<InstanceCountTrendDto> instanceCountTrendList) {
        if (CollectionUtils.isNotEmpty(filterDate) && filterDate.size() == 2) {
            DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
            LocalDateTime beginDate = LocalDateTime.parse(filterDate.get(0), formatter).withMinute(0).withSecond(0);
            LocalDateTime endDate = LocalDateTime.parse(filterDate.get(1), formatter).withMinute(0).withSecond(0);
            Iterator<InstanceCountTrendDto> iterator = instanceCountTrendList.iterator();
            InstanceCountTrendDto instanceCountTrendDto;
            int year;
            int month;
            int day;
            int hour;
            LocalDateTime dateTime;
            while (iterator.hasNext()) {
                instanceCountTrendDto = iterator.next();
                year = Integer.parseInt(instanceCountTrendDto.getGroupDate().getOrDefault(DatabaseUtils.getFieldName(InstanceCountTrendDto::getYear), "1991").toString());
                month = Integer.parseInt(instanceCountTrendDto.getGroupDate().getOrDefault(DatabaseUtils.getFieldName(InstanceCountTrendDto::getMonth), "1").toString());
                day = Integer.parseInt(instanceCountTrendDto.getGroupDate().getOrDefault(DatabaseUtils.getFieldName(InstanceCountTrendDto::getDay), "1").toString());
                hour = Integer.parseInt(instanceCountTrendDto.getGroupDate().getOrDefault(DatabaseUtils.getFieldName(InstanceCountTrendDto::getHour), "1").toString());
                dateTime = LocalDateTime.of(year, month, day, hour, 0);
                if (dateTime.isBefore(beginDate) || dateTime.isAfter(endDate)) {
                    iterator.remove();
                }
            }
        }
    }

    private void setInstanceCountSubView(InstanceCountTrendView instanceCountTrendView, List<InstanceCountTrendDto> subCountDto, InstanceTrendSearchParam param) {
        Map<String, List<InstanceCountTrendDto>> dimension2CountMap = subCountDto.stream().collect(Collectors.groupingBy(item -> {
            StringBuilder stringBuffer = new StringBuilder();
            if (CollectionUtils.isNotEmpty(param.getDateLineKeys())) {
                for (int i = 0; i < param.getDateLineKeys().size(); i++) {
                    if (i > 0) {
                        stringBuffer.append("-");
                    }
                    stringBuffer.append(item.getGroupDate().get(param.getDateLineKeys().get(i)));
                }
            }
            return stringBuffer.toString();
        }));
        List<InstanceCountTrendView> subViewList = new ArrayList<>();
        InstanceCountTrendView subView;
        for (Map.Entry<String, List<InstanceCountTrendDto>> entry : dimension2CountMap.entrySet()) {
            subView = new InstanceCountTrendView();
            subView.setDate(entry.getKey());
            subView.setCount(entry.getValue().get(entry.getValue().size() - 1).getCount());
            subViewList.add(subView);
        }
        Collections.sort(subViewList, (o1, o2) -> {
            String[] key1Arr = o1.getDate().split("-");
            String[] key2Arr = o2.getDate().split("-");
            for (int i = 0; i < key1Arr.length; i++) {
                if (StringUtils.equals(key1Arr[i], "null") || StringUtils.equals(key2Arr[i], "null")) {
                    return -1;
                }
                if (key1Arr[i] != null && key2Arr[i] != null && !key1Arr[i].equals(key2Arr[i])) {
                    return Integer.valueOf(key1Arr[i]).compareTo(Integer.valueOf(key2Arr[i]));
                }
            }
            return 1;
        });
        if (subViewList.size() > 0) {
            instanceCountTrendView.setCount(subViewList.get(subViewList.size() - 1).getCount());
        }
        instanceCountTrendView.setSubViews(subViewList);
    }
}
